<> <> <> <> <> DIRECTORY XeroxDecompress USING [DecompressInfo, DoneProc, InitProc, NextLineProc], <> PrincOpsUtils USING [LongCopy], Basics USING [bitsPerWord, BITAND, BITSHIFT, BITXOR, LowHalf]; XeroxDecompressImpl: PROGRAM IMPORTS Basics, PrincOpsUtils EXPORTS XeroxDecompress = BEGIN <> nBits: CARDINAL = Basics.bitsPerWord; nNibs: CARDINAL = 4; -- Number of nibbles in a word bitGotMask: ARRAY [0..nBits) OF CARDINAL = [ 177777B, 77777B, 37777B, 17777B, 7777B, 3777B, 1777B, 777B, 377B, 177B, 77B, 37B, 17B, 7B, 3B, 1B]; bitGetMask: ARRAY [0..nBits] OF CARDINAL = [ 0, 1B, 3B, 7B, 17B, 37B, 77B, 177B, 377B, 777B, 1777B, 3777B, 7777B, 17777B, 37777B, 77777B, 177777B]; maxLINCount: CARDINAL = 15; <> axx: ARRAY [0..4) OF CARDINAL = [8, 4, 2, 1]; enc: CARDINAL = 2; -- ENC mode eoi: CARDINAL = 113; -- End of image htn: CARDINAL = 3; -- HTN mode lin: CARDINAL = 1; -- LIN mode raw: CARDINAL = 0; -- Raw (ie., no encoding) soi: CARDINAL = 112; -- Start of image <<============>> WrdPtr: TYPE = LONG POINTER TO WORD; BitPosition: TYPE = RECORD [ bufPtr: WrdPtr _ NIL, -- Word pointer bitBuf: CARDINAL _ 0, -- Current bit buffer bitPos: CARDINAL _ 0, -- Current bit position within BitBuf bitCount: LONG CARDINAL _ 0 -- Bit count ]; BitPositionPtr: TYPE = LONG POINTER TO BitPosition; <<================ used for Statictics>> DecompressStat: TYPE = RECORD [ total: LONG CARDINAL, compressed: LONG CARDINAL, raw: CARDINAL, enc: CARDINAL, lin: CARDINAL, htn: CARDINAL]; <> <> <> <> <<================>> inputPos: BitPosition _ []; -- Current input position samplePos: BitPosition _ []; -- Current position in sample buffer currLinePos:BitPosition _ []; -- Bit position of current scan line in sample pvLinePos: BitPosition _ []; -- Bit position of last scan line in the sample bufferPtr: WrdPtr _ NIL; -- ptr to buffer for previous line zeroBuffPtr: LONG POINTER TO ARRAY [0..0) OF WORD _ NIL; scanLength: CARDINAL _ 0; -- Scan length of input scanBitLen: CARDINAL _ 0; -- Scan length of output in bits scanWordLen: CARDINAL _ 0; -- Scan length in words nRange: CARDINAL _ 0; scnLine: CARDINAL _ 0; -- Count of scan lines linCount: CARDINAL _ 0; -- # of consecutive LIN mode nextMode: CARDINAL _ 0; eoiFound: BOOLEAN _ FALSE; decZone: UNCOUNTED ZONE _ Heap.Create [initial: 1]; Error: PUBLIC ERROR [line: CARDINAL] = CODE; <> GetN: PROCEDURE [bits: INTEGER, pos: BitPositionPtr _ @inputPos] RETURNS [val: CARDINAL] = { OPEN i: pos^; <> remainder: INTEGER; currPos: INTEGER _ i.bitPos + bits; -- current bit position i.bitCount _ i.bitCount + bits; -- update current bit count remainder _ nBits - currPos; <> SELECT TRUE FROM (remainder > 0) => { -- Incomplete val _ Basics.BITSHIFT[i.bitBuf, -remainder]; i.bitBuf _ Basics.BITAND[i.bitBuf, bitGetMask[remainder]]; i.bitPos _ currPos; }; (remainder = 0) => { -- Full val _ i.bitBuf; i.bufPtr _ i.bufPtr + 1; i.bitBuf _ i.bufPtr^; i.bitPos _ 0; }; ENDCASE => { -- Overflow remPos: INTEGER _ nBits + remainder; i.bitPos _ -remainder; i.bufPtr _ i.bufPtr + 1; val _ Basics.BITSHIFT[i.bitBuf, i.bitPos] + Basics.BITSHIFT[i.bufPtr^, -remPos]; i.bitBuf _ Basics.BITAND[i.bufPtr^, bitGetMask[remPos]]; }; }; -- GetN PutN: PROCEDURE [val: CARDINAL, bits: INTEGER] = { OPEN s: samplePos; <> remainder: INTEGER; currPos: INTEGER _ s.bitPos + bits; -- current bit position s.bitCount _ s.bitCount + bits; -- update current bit count remainder _ nBits - currPos; <> SELECT TRUE FROM (remainder > 0) => { -- Incomplete s.bitBuf _ s.bitBuf + Basics.BITSHIFT[val, remainder]; s.bitPos _ currPos; }; (remainder = 0) => { -- Full s.bufPtr^ _ s.bitBuf + val; s.bufPtr _ s.bufPtr + 1; s.bitBuf _ 0; s.bitPos _ 0; }; ENDCASE => { -- Overflow s.bitPos _ -remainder; s.bufPtr^ _ s.bitBuf + Basics.BITSHIFT[val, remainder]; s.bitBuf _ Basics.BITSHIFT[val, nBits - s.bitPos]; s.bufPtr _ s.bufPtr + 1; }; }; -- PutN SetInputPos: PROCEDURE[oldPos: BitPosition] RETURNS[newPos:BitPosition] = INLINE { <> newPos _ oldPos; newPos.bitBuf _ Basics.BITAND[newPos.bufPtr^, bitGotMask[newPos.bitPos]]; }; -- SetInputPos ProcessHTN: PROCEDURE = INLINE { -- This routine will process the HTN mode line. pvRange: CARDINAL _ 0; currRange: CARDINAL _ 0; currLineGet: BitPosition; bits: CARDINAL _ scanBitLen; <> samplePos _ currLinePos; currLineGet _ SetInputPos[currLinePos]; WHILE bits >= nRange DO pvRange _ Basics.BITXOR[GetN[nRange, @currLineGet], pvRange]; PutN[pvRange, nRange]; bits _ bits - nRange; ENDLOOP; <> IF bits > 0 THEN PutN[Basics.BITXOR[GetN[bits, @currLineGet], Basics.BITSHIFT[pvRange, INTEGER[bits] - nRange]], bits]; <> }; -- ProcessHTN ProcessLIN: PROCEDURE = INLINE { -- Process scan line encoded in LIN mode. currPtr: WrdPtr _ currLinePos.bufPtr; pvPtr: WrdPtr _ pvLinePos.bufPtr; <> <> <> FOR i: CARDINAL IN [0..scanWordLen) DO currPtr^ _ Basics.BITXOR[currPtr^, pvPtr^]; currPtr _ currPtr + 1; pvPtr _ pvPtr + 1; ENDLOOP; <> }; -- ProcessLIN PutZerosAndNibble: PROCEDURE [n: CARDINAL, nibble: CARDINAL] = { FOR i: CARDINAL IN [0..n) DO PutN[0, 4]; ENDLOOP; PutN[nibble, 4]; }; PutManyZeros: PROCEDURE [count: CARDINAL] = { OPEN s: samplePos; <> rem: CARDINAL; IF count <= nBits THEN {PutN[0, count]; RETURN;}; IF s.bitPos # 0 THEN { count _ count - (nBits - s.bitPos); -- update count PutN[0, nBits - s.bitPos]; -- word align }; PrincOpsUtils.LongCopy[zeroBuffPtr, count/nBits, s.bufPtr]; s.bufPtr _ s.bufPtr + count/nBits; rem _ count MOD nBits; s.bitCount _ s.bitCount + count - rem; -- update bit count IF rem # 0 THEN PutN[0, rem]; }; -- PutManyZeros PutManyZerosAndNibble: PROCEDURE [n: CARDINAL, nibble: CARDINAL] = INLINE { <> PutManyZeros[n * 4]; PutN[nibble, 4]; }; ZeroFill: PROCEDURE = INLINE { -- Zero fill the rest of the line. PutN is not used for efficiency. PutManyZeros[scanBitLen - (Basics.LowHalf[samplePos.bitCount - currLinePos.bitCount])]; }; MoveLines: PROCEDURE = INLINE { OPEN s: samplePos; <> ptr: WrdPtr _ s.bufPtr; FOR i: CARDINAL IN [0..scanLength / nBits) DO ptr^ _ GetN[nBits]; ptr _ ptr + 1; ENDLOOP; s.bufPtr _ ptr; s.bitCount _ s.bitCount + scanLength; IF scanBitLen # scanLength THEN PutN[0, scanBitLen - scanLength]; }; -- MoveLines CompressedNextLine: PUBLIC XeroxDecompress.NextLineProc = { <> ENABLE UNWIND => CompressedDone[h]; code: CARDINAL; mode: CARDINAL; nibble: CARDINAL; t: INTEGER; IF eoiFound THEN RETURN [FALSE]; <> samplePos.bitPos _ 0; samplePos.bitBuf _ 0; samplePos.bufPtr _ out; samplePos.bitCount _ 0; currLinePos _ samplePos; -- start at sample[0] pvLinePos _ [bufferPtr, 0,0,0]; -- remember start of previous line mode _ nextMode; IF mode > 3 THEN ERROR Error[--badLCC,-- scnLine]; <> IF mode = raw THEN { MoveLines[]; <> nextMode _ GetN[8]} -- next LCC or EOI ELSE { -- Decode DO -- get run code _ GetN[4]; IF (8 <= code) AND (code <= 11) THEN PutZerosAndNibble[0, axx[code MOD 4]] -- 4-bit codes ELSE { -- 8-bit codes code _ code * 16 + GetN[4]; -- form 8-bit code IF code = soi THEN ERROR Error[--badSOI,-- scnLine]; IF (code <= 3) OR (code = eoi) THEN GOTO GotAllRuns ELSE IF (4 <= code) AND (code <= 147B) THEN PutZerosAndNibble[code / 4, axx[code MOD 4]] ELSE IF (150B <= code) AND (code <= 177B) THEN { t _ (code / 2) MOD 16; IF t = 4 THEN PutZerosAndNibble[code MOD 2, 3] ELSE PutZerosAndNibble[code MOD 2, t] } <<200B <= code <= 277B are covered by 4-bit codes >> ELSE { --300B <= code <= 377B: 12 bit codes g: CARDINAL _ Basics.BITAND[code, 77B]; nibble _ GetN[4]; IF nibble = 0 THEN { IF g = 0 THEN PutN[0, 4] ELSE PutManyZerosAndNibble[(100B * g) - 1, 0] } ELSE PutZerosAndNibble[g, nibble] } }; -- 8 bit codes REPEAT GotAllRuns => { nextMode _ code; IF samplePos.bitCount - currLinePos.bitCount > scanLength THEN ERROR Error[--lineTooLong,-- scnLine]; ZeroFill[]; -- Fill Scan line with 0's }; -- GotAllRuns ENDLOOP; -- get run }; -- Decode <> SELECT mode FROM lin => { linCount _ linCount + 1; IF linCount > maxLINCount THEN ERROR Error[--tooManyLIN,-- scnLine]; ProcessLIN[]; }; htn => {linCount _ 0; ProcessHTN[]; }; enc => {linCount _ 0; --encLines _ encLines + 1-- }; ENDCASE => linCount _ 0; scnLine _ scnLine + 1; PrincOpsUtils.LongCopy[from: out, nwords: scanWordLen, to: bufferPtr]; IF nextMode = eoi THEN eoiFound _ TRUE; valid _ TRUE; }; -- CompressedNextLine CompressedInit: PUBLIC XeroxDecompress.InitProc = { ENABLE UNWIND => decZone.FREE[@h]; reserved: CARDINAL; eoiFound _ FALSE; h _ decZone.NEW[XeroxDecompress.DecompressInfo]; h.flavor _ compressed; h.private _ @v; <> inputPos.bitPos _ IF (v.startIndex MOD 2) = 0 THEN 0 ELSE 8; inputPos.bufPtr _ LOOPHOLE[v.blockPointer + v.startIndex/2]; inputPos.bitBuf _ inputPos.bufPtr^; inputPos.bitCount _ 0; <> <> scnLine _ 0; reserved _ GetN[16]; nRange _ GetN[16]; scanLength _ GetN[16]; IF (reserved # 0) OR (nRange < 5) OR (scanLength MOD 8 # 0) THEN ERROR Error[--badHeader,-- scnLine]; <> scanWordLen _ (scanLength + nBits - 1) / nBits; scanBitLen _ scanWordLen * nBits; <> linCount _ maxLINCount + 1; IF GetN[8] # soi THEN ERROR Error[--noSOI,-- scnLine]; nextMode _ GetN[8]; -- first LCC bufferPtr _ Heap.MakeNode[decZone, scanWordLen]; zeroBuffPtr _ Heap.MakeNode[decZone, scanWordLen]; FOR i: CARDINAL IN [0..scanWordLen) DO zeroBuffPtr[i] _ 0; ENDLOOP; h.scanLength _ scanLength; }; -- CompressedInit CompressedDone: PUBLIC XeroxDecompress.DoneProc = { decZone.FREE[@h]; Heap.FreeNode[decZone, bufferPtr]; Heap.FreeNode[decZone, zeroBuffPtr]; <> <> }; END. <<>> <> <<8Mar84 - Okamoto - Created.>> <<16Nov84 - castillo - renamed to XeroxDecompressImpl; moved around to make use of the Decompress interface.>> <<4Jan85 - castillo - updated to new parm in Init, byte alignment assumed; added eoiFound.>> <<18Apr85 - castillo - stuffed scanLength in handle at Init time.>>