-- File: PressNetCompressSend.mesa: Routines for sending a file to a printing server.
-- Last Edited: November 3, 1981 11:49 AM By: GWilliams
--This is a program that runs stand-alone. It reads a file input to a prompt and writes
-- file "foo.gw". It is a test that uses BitBlt to create a run-length encoded version of the input file.



DIRECTORY
InlineDefs USING [BITAND, LowHalf],
IODefs USING[ReadLine, WriteLine, WriteString],
PressNetDefs,
SegmentDefs USING[DataSegmentHandle, DefaultBase, DeleteDataSegment, NewDataSegment, Read, SegmentAddress, WriteAppend],
StreamDefs USING[NewByteStream, DiskHandle, GetPosition, ReadBlock, StreamPosition, WriteBlock];
PressNetCompressor: PROGRAM
IMPORTS InlineDefs, IODefs, SegmentDefs, StreamDefs
EXPORTS PressNetDefs =
BEGIN OPEN InlineDefs, IODefs, SegmentDefs, StreamDefs;
CompressSpec: RECORD =
[src1:POINTER,--this buffer is overwritten
src2:POINTER, --this buffer is not destroyed
nibblesArray:POINTER,--this buffer has the nibble specs and must be supplied by caller
srcLen:CARDINAL--length of source buffers
maxNibbleIx:CARDINAL--max index into nibblesArray
nibbleSize:CARDINAL--break compressed image into this size of nibble.
nibblesCt:CARDINAL--number of nibble specs returned
];
NibbleSpecType: TYPE = {atom, run};--specifies either one nibble or many
NibbleRunSpec: TYPE = MACHINE DEPENDENT RECORD
[descriptorType: SELECT type: NibbleSpecType FROM
run=> [color: COLOR, nibbleCt: [0..77B]],
atom=> [thisNibble: [0..177B]],
ENDCASE
];
];
headerBufferSeg: FileSegmentHandle;--to hold page one of Press.bits
headerFh: FileHandle;
headerAddress: POINTER TO ARRAY [0..1024) OF WORD;
headerInCore: BOOLEAN ← FALSE;
filename: STRING ← [200];
CompressErrCode: TYPE = {badBitsFile, fileNotFound, notEnoughScans};
compressAbort: ERROR[compressErrCode: CompressErrCode] = CODE;
--
Procs

CompressorDriver: PUBLIC PROC[] --RETURNS[okToProceed: BOOLEAN ← FALSE]--=
--Raises no signals or errors
BEGIN
nibbleSize: CARDINAL ← 6;--make the nibbles 6 bits wide
nibbleCt: [0..77B];
maxNibbleCt: CARDINAL;
i: CARDINAL;
--
bufferWordLen: CARDINAL;this is now scanLineLength
h, hOut: DiskHandle;
endIn, endOut: BOOLEAN ← FALSE;
srcASeg, srcBSeg, nibblesSeg: DataSegmentHandle;
wordsRead, wordsWritten: CARDINAL;
srcA, srcB: DESCRIPTOR FOR ARRAY OF WORD;
nibblesBuffer: DESCRIPTOR FOR ARRAY OF NibbleSpec;
streamPosition: StreamPosition;
nPages: CARDINAL;--# of printed pages (or separations)
thisPageG: PageGptr ← NIL;--this points into headerAddress array, I assume ~(.GT. 1K)

--
scan line info
scanLineLength: CARDINAL;--in 16-bit words
bandWidth: CARDINAL = 16;
totalScans: CARDINAL;
localState: CompressErrCode ← noError;
BEGIN
WriteString["Filename to read: "];
ReadLine[filename];

WriteLine["Writing file Foo.GW."];

[nPages, thisPageG] ← GetPageG[1! abort => GOTO exit];
[h] ← NewByteStream[filename, Read];--open file for testing.
[hOut] ← NewByteStream["Foo.GW", WriteAppend];

FOR i IN [1..nPages]
DO

[nPages, thisPageG] ← GetPageG[i! compressAbort => {localState ← compressErrCode; GOTO exit}];
scanLineLength ← thisPageG.BitWc;
totalScans ← bandWidth * ((thisPageG.LastBand - thisPageG.FirstBand) + 1)

--the scan line length may change from page to page.
srcASeg ← NewDataSegment[DefaultBase, (scanLineLength+255)/256];
srcA ← DESCRIPTOR[SegmentAddress[srcASeg], scanLineLength];
srcBSeg ← NewDataSegment[DefaultBase, (scanLineLength+255)/256];
srcB ← DESCRIPTOR[SegmentAddress[srcBSeg], scanLineLength];
--calculate the max possible size of the nibblesSeg and set up pointer to it.
maxNibbleCt ← (scanLineLength*16 + (nibbleSize-1))/nibbleSize;
nibbleSeg ← NewDataSegment[DefaultBase, (maxNibbleCt + 255)/256];
nibblesBuffer ← DESCRIPTOR[SegmentAddress[nibbleSeg], maxNibbleCt];

--change this to get 1K buffers since the scan lines are padded anyway and loop till EOF
FOR iScans: CARDINAL IN [0..totalScans)
DO
--
alternate buffers on fill
wordsRead ← ReadBlock[h, (IF (BITAND[iScans, 1] = 0) THEN srcA ELSE srcB), scanLineLength];
endIn ← h.endof[h];
--filll in compressSpec
Compressor[compressSpec, wordsRead];

FOR iNibblesCt: CARDINAL IN [0..compressSpec.nibblesCt)
DO
hOut.put[hOut, nibblesBuffer[iNibblesCt]]
ENDLOOP;
IF endIn THEN {localErr ← notEnoughScans; GOTO exit};
ENDLOOP;

ENDLOOP;--this is the page loop

localState ← allOK;
GOTO exit;--for cleanup
EXITS
exit => SELECT localState FROM
badBitsFile => WriteLine["Doesn’t look like a press.bits format file"L];--ERROR
fileNotFound => NUL;
notEnoughScans => {WriteLine["Input file ended before all scans were processed."L];
notEnoughScans, allOK =>
DeleteDataSegment[bufferSeg];
h.destroy[h];
h.destroy[hOut];
Unlock[headerBufferSeg];
SwapOut[headerBufferSeg];
DeleteFileSegment[headerBufferSeg];
headerInCore ← FALSE;

ENDLOOP;
END;
END;
--of CompressorDriver

GetPageG:
PROC[pageNum: CARDINAL] RETURNS[numPages: CARINDAL, pageGpt: PageGptr]=
BEGIN
IF ~headerInCore THEN
{fH ← NewFile[filename, Read, OldFileOnly!
FileNameError => {WriteString["File "L]; WriteString[filename]; WriteString[" is required"L];
compressAbort[fileNotFound];};];

headerBufferSeg ← NewFileSegment[fH, defaultBase, 4, ];--point to one page; default access, 1K
SwapIn[headerBufferSeg];--get it into core
headerAddress ← LOOPHOLE[SegmentAddress[headerBufferSeg]];--find out where it is
headerInCore ← TRUE;
};

numPages ← headerAddress[0];
IF headerAddress[3] # PressPassword THEN GOTO inconsistentFile;
pageGpt ← LOOPHOLE[@headerAddress[4] + ((pageNum-1)*PageGLength), pageGptr];
EXITS
inconsistentFile => {Unlock[headerBufferSeg];
SwapOut[headerBufferSeg];
DeleteFileSegment[headerBufferSeg];
headerInCore ← FALSE;
compressAbort[badBitsFile]};
END;--
GetPageG


Compressor
: PROC[compressSpec: CompressSpec]=
--
takes two src’s and xor’s them, destroying one of them
{


};

--initilization code (again, for testing only)

--SendBits[NIL, 0];
CompressorDriver[];

END.
-- PressNetCompressor.mesa


-- Last Edited: September 30, 1981 10:09 AM By: GWilliams
-- File: PressNetSender.mesa: Routines for sending a file to a printing server.
--Debugging streams stuff!
--This is a program that runs stand-alone. It reads a file input to a prompt and writes
-- file "foo.gw". It is a test that uses fast i/o (Read/Write block vs Get/Put byte) in
-- order to ship stuff over the net using EFTPSendBlock