PDInterpReaderImpl.mesa
Michael Plass, April 4, 1984 12:48:53 pm PST
Last Edited by: Pier, November 22, 1983 2:45 pm
Last Edited by: Lamming, December 9, 1983 1:27 pm
DIRECTORY
Environment, Inline, PDInterpBasic, PDFileFormat, PDInterpBitmap, PDInterpReader, PDInterpSysCalls, Mopcodes, Heap, PDPrinter, PDPrinterRpcControl, MesaRPC, OthelloDefs, Process;
PDInterpReaderImpl: MONITOR
IMPORTS Inline, PDInterpBitmap, PDInterpSysCalls, Heap, PDPrinterRpcControl, MesaRPC, OthelloDefs, Process
EXPORTS PDInterpReader, PDPrinter
= BEGIN OPEN PDInterpReader;
bitsPerWord: NAT = Environment.bitsPerWord;
zone: UNCOUNTED ZONE = Heap.systemZone;
currentHandle: Handle ← NIL;
NewClient: CONDITION;
BufferSpaceAvailable: CONDITION;
NewDataAvailable: CONDITION;
TransmitBlock: PUBLIC ENTRY PROC [dataBlock: PDPrinter.DataBlock]
RETURNS [response: PDPrinter.Response] = {
ENABLE UNWIND => NULL;
IF currentHandle = NIL THEN {
dataPtr: LONG POINTER ← @(dataBlock.buffer);
herald: LONG POINTER TO PDFileFormat.Herald ← dataPtr;
private: Private ← zone.NEW[PrivateRep];
PDInterpSysCalls.SetDisplayLights[105];
OthelloDefs.WriteLine["New client request"];
IF dataBlock.wordIndex # 0 THEN RETURN[[nextWordIndex: -1, status: serverAbort, currentPage: 0]];
currentHandle ← zone.NEW[Rep ← [
herald: herald^,
image: [0,FALSE,FALSE,FALSE,black,0,0,0,0],
bandNumber: 0,
sMinBand: 0,
sSizeBand: 0,
colorType: none,
colorTileLoadAddress: -1,
priority: 0,
loadWords: 0,
private: private,
index: 0,
page: 0,
pass: 0,
status: betweenPages,
warningCount: 0
]];
IF dataBlock.wordCount < SIZE[PDFileFormat.Herald] THEN currentHandle.status ← unexpectedEOF
ELSE CheckHerald[currentHandle];
IF currentHandle.status # betweenPages THEN {
errorStatus: PDInterpBasic.Status ← currentHandle.status;
zone.FREE[@private];
zone.FREE[@currentHandle];
RETURN[[nextWordIndex: -1, status: errorStatus, currentPage: 0]];
};
currentHandle.index ← SIZE[PDFileFormat.Herald];
currentHandle.sSizeBand ← herald.bandSSize;
{ENABLE
UNWIND => {
zone.FREE[@private];
zone.FREE[@currentHandle];
};
AllocateSpace[currentHandle];
};
NOTIFY NewClient;
RETURN[[nextWordIndex: currentHandle.index, status: currentHandle.status, currentPage: 0]];
}
ELSE {
private: Private ← currentHandle.private;
BufferEndIndex: PROC RETURNS [INT] = {
wordsPassedBy: INT = private.bufferWordPointer-private.bufferOriginPointer;
wordsToEndOfBuffer: INT = private.bufferWordsAllocated-wordsPassedBy;
RETURN [currentHandle.index + wordsToEndOfBuffer];
};
oldEndIndex: INT = currentHandle.index + private.bufferWordCount;
IF dataBlock.wordIndex # oldEndIndex THEN {
RETURN[[
nextWordIndex: oldEndIndex,
status: currentHandle.status,
currentPage: currentHandle.page
]];
};
WHILE BufferEndIndex[] < dataBlock.wordIndex + dataBlock.wordCount DO
WAIT BufferSpaceAvailable;
ENDLOOP;
BlockTransfer[source: @(dataBlock.buffer), count: dataBlock.wordCount, dest: private.bufferWordPointer+private.bufferWordCount];
private.bufferWordCount ← private.bufferWordCount + dataBlock.wordCount;
NOTIFY NewDataAvailable;
IF dataBlock.wordCount=0 THEN { -- used to time interpretter
OthelloDefs.WriteLine["Cranking up interp"];
NOTIFY NewDataAvailable;
Process.Pause[Process.MsecToTicks[1000]];
};
RETURN[[
nextWordIndex:
IF currentHandle.status = transmissionComplete
THEN -1
ELSE oldEndIndex + dataBlock.wordCount,
status: currentHandle.status,
currentPage: currentHandle.page
]];
};
};
CheckHerald: INTERNAL PROC [handle: Handle] = {
IF handle.herald.maxLoadWord > 100000 THEN
handle.status ←           unreasonableLoadSize;
IF NOT (handle.herald.copies IN [1..200]) THEN
handle.status ←           unreasonableNumberOfCopies;
IF NOT (handle.herald.imageSSize IN [80..32767])
OR NOT (handle.herald.imageFSize IN [80..32767]) THEN
handle.status ←           unreasonableImageSize;
IF NOT (handle.herald.bandSSize IN [8..32767]) THEN
handle.status ←           unreasonableBandSSize;
IF NOT (handle.herald.sResolution IN [10..10000])
OR NOT (handle.herald.fResolution IN [10..10000]) THEN
handle.status ←           unreasonableResolution;
IF handle.herald.version # PDFileFormat.versionValue THEN
handle.status ←           wrongFormatVersion;
IF handle.herald.password # PDFileFormat.passwordValue THEN
handle.status ←           invalidPassword;
};
AllocateSpace: INTERNAL PROC [handle: Handle] = {
ENABLE UNWIND => NULL;
private: Private ← handle.private;
bufferWords: INT ← (Inline.LongMult[handle.herald.bandSSize, (handle.herald.imageFSize+bitsPerWord-1)/bitsPerWord]+100)*2;
private.loadPointer ← PDInterpSysCalls.AllocateSpace[handle.herald.maxLoadWord+bufferWords];
private.loadWordsAllocated ← handle.herald.maxLoadWord;
private.bufferWordPointer ← private.bufferOriginPointer ← private.loadPointer + private.loadWordsAllocated;
private.bufferWordsAllocated ← bufferWords;
private.bufferWordCount ← 0;
};
Open: PUBLIC ENTRY PROC RETURNS [handle: Handle] = {
ENABLE UNWIND => NULL;
interfaceName: MesaRPC.InterfaceName ← [instance: "Belle.auto"L];
PDInterpSysCalls.SetDisplayLights[100];
OthelloDefs.WriteLine["Exporting PD server Belle"];
PDPrinterRpcControl.ExportInterface[interfaceName: interfaceName, user: "Belle.auto"L, password: MesaRPC.MakeKey
["4SAPF433"L]
];
PDInterpSysCalls.SetDisplayLights[101];
OthelloDefs.WriteLine["Soliciting client"];
WHILE currentHandle = NIL DO
WAIT NewClient;
ENDLOOP;
PDInterpSysCalls.SetDisplayLights[107];
OthelloDefs.WriteLine["Got a client"];
handle ← currentHandle;
};
WaitForClientToFindOutWeAreDone: ENTRY PROC = {
WAIT NewDataAvailable;
};
Close: PUBLIC ENTRY PROC [handle: Handle] RETURNS [Handle ← NIL] = {
ENABLE UNWIND => NULL;
private: Private ← handle.private;
PDInterpSysCalls.SetDisplayLights[108];
OthelloDefs.WriteLine["Finishing with client"];
IF handle # currentHandle THEN ERROR;
PDPrinterRpcControl.UnexportInterface[];
currentHandle ← NIL;
IF private.loadPointer # NIL THEN PDInterpSysCalls.FreeSpace[private.loadPointer];
zone.FREE[@private];
zone.FREE[@handle];
PDInterpSysCalls.SetDisplayLights[109];
OthelloDefs.WriteLine["Finished"];
};
ColorTileFromLoad: PUBLIC PROC [handle: Handle, colorTileLoadAddress: INT, scratchPointer: LONG POINTER, scratchWords: INT] RETURNS [PDInterpBitmap.Tile] = {
private: Private = handle.private;
tile: LONG POINTER TO PDFileFormat.Tile = private.loadPointer + colorTileLoadAddress;
words: INT = Inline.LongMult[tile.sSize, (tile.fSize+(bitsPerWord-1))/bitsPerWord];
bitmap: PDInterpBitmap.BitmapDesc← PDInterpBitmap.Reshape[
tile + SIZE[PDFileFormat.Tile],
words,
[tile.sMin, tile.fMin, tile.sSize, tile.fSize]
];
RETURN [PDInterpBitmap.CreateTile[
rectangle: [tile.sMin, tile.fMin, tile.sSize, tile.fSize],
phase: tile.phase,
rasterPointer: tile + SIZE[PDFileFormat.Tile],
scratchPointer: scratchPointer,
scratchWords: scratchWords
]];
};
BlockTransfer: PROC [source: LONG POINTER, count: CARDINAL, dest: LONG POINTER]
= MACHINE CODE {Mopcodes.zBLTL};
LongBlockTransfer: PROC [source: LONG POINTER, count: INT, dest: LONG POINTER] = {
WHILE count > LAST[CARDINAL] DO
BlockTransfer[source, LAST[CARDINAL], dest];
source ← source + LAST[CARDINAL];
dest ← dest + LAST[CARDINAL];
count ← count - LAST[CARDINAL];
ENDLOOP;
BlockTransfer[source, count, dest];
};
Private: TYPE = LONG POINTER TO PrivateRep;
PrivateRep: PUBLIC TYPE = RECORD [
loadPointer: LONG POINTER ← NIL,
loadWordsAllocated: INT ← 0,
bufferOriginPointer: LONG POINTER ← NIL,
bufferWordsAllocated: INT ← 0,
bufferWordPointer: LONG POINTER ← NIL,
bufferWordCount: INT ← 0
The buffer variables satisfy the invariants
(bufferWordPointer + i)^ = InputFileWord[handle.index+i], i IN [0..bufferWordCount)
handle.index+bufferWordCount <= inputFileSizeInWords
bufferWordPointer-bufferOriginPointer >= 0
bufferWordCount + (bufferWordPointer-bufferOriginPointer) <= bufferWordsAllocated
where InputFileWord[k] stands for the kth word of the input file.
];
FillBuffer: ENTRY PROC [handle: Handle, wordsNeeded: INT] RETURNS [wordsRemovedFromFront: INT] = {
wordsRemovedFromFront ← InternalFillBuffer[handle, wordsNeeded];
};
InternalFillBuffer: INTERNAL PROC [handle: Handle, wordsNeeded: INT] RETURNS [wordsRemovedFromFront: INT] = {
private: Private ← handle.private;
wordsRemovedFromFront ← (private.bufferWordPointer-private.bufferOriginPointer);
LongBlockTransfer[source: private.bufferWordPointer, count: private.bufferWordCount, dest: private.bufferOriginPointer];
private.bufferWordPointer ← private.bufferOriginPointer;
NOTIFY BufferSpaceAvailable;
WHILE private.bufferWordCount < wordsNeeded DO
WAIT NewDataAvailable;
ENDLOOP;
};
BlockDescription: TYPE = RECORD [pointer: LONG POINTER, words: CARDINAL];
ReadLocate: ENTRY PROC [handle: Handle, words: INT]
RETURNS [blockDescription: BlockDescription] = {
The buffer storage may get re-used with the next ReadLocate or ReadBlock;
private: Private ← handle.private;
IF private.bufferWordCount < words THEN [] ← InternalFillBuffer[handle, words];
blockDescription.pointer ← private.bufferWordPointer;
blockDescription.words ← MIN[private.bufferWordCount, words];
private.bufferWordPointer ← private.bufferWordPointer + blockDescription.words;
private.bufferWordCount ← private.bufferWordCount - blockDescription.words;
handle.index ← handle.index + blockDescription.words;
};
ReadBlock: ENTRY PROC [handle: Handle, dest: LONG POINTER, words: INT] = {
private: Private ← handle.private;
WHILE words > 0 DO
inBuffer: INTMIN[private.bufferWordCount, words];
BlockTransfer[source: private.bufferWordPointer, count: inBuffer, dest: dest];
private.bufferWordPointer ← private.bufferWordPointer + inBuffer;
private.bufferWordCount ← private.bufferWordCount - inBuffer;
handle.index ← handle.index + inBuffer;
dest ← dest + inBuffer;
words ← words - inBuffer;
IF words > 0 THEN [] ← InternalFillBuffer[handle, MIN[words, PDPrinter.maxBlockSize]];
ENDLOOP;
};
CheckBB: PROC [handle: Handle, sMin, fMin, sSize, fSize: CARDINAL, errorWordCount: INT] = {
IF LONG[sMin] + sSize > handle.herald.imageSSize
OR LONG[fMin] + fSize > handle.herald.imageFSize
OR fMin < handle.image.fMinPage
OR fMin + fSize > handle.image.fMinPage + handle.image.fSizePage
THEN RaisePDError[handle, objectOutOfBounds, errorWordCount];
IF sMin + sSize <= handle.sMinBand
OR sMin >= handle.sMinBand+handle.sSizeBand THEN {
RaisePDWarning[handle, objectOutOfBand, errorWordCount];
};
};
Get: PUBLIC PROC [handle: Handle] RETURNS [CommandBuffer] = {
private: Private ← handle.private;
command: PDFileFormat.Command;
BadLoadReference: PROC [dataWords: INT] = {
RaisePDError[handle, badLoadReference, SIZE[PDFileFormat.Command]+dataWords];
};
IF handle.priority = LAST[INT] THEN {
ans: CommandBuffer.stateChange;
ans.loadChangeStart ← ans.loadChangeLength ← 0;
handle.sMinBand ← handle.sMinBand + handle.sSizeBand;
handle.bandNumber ← handle.bandNumber + 1;
handle.priority ← 0;
handle.colorType ← ink;
ans.whatChanged ← bandChange;
IF handle.bandNumber = handle.image.nBands THEN {
ans.whatChanged ← imageEnd;
handle.colorType ← none;
handle.status ← betweenPages;
};
RETURN [ans];
};
ReadBlock[handle, @command, SIZE[PDFileFormat.Command]];
WITH command SELECT FROM
imagingCommand: PDFileFormat.Command.imaging => {
IF handle.colorType = none THEN {
RaisePDError[handle, missingStartImage, SIZE[PDFileFormat.Command]];
ERROR
};
SELECT imagingCommand.com FROM
maskSamplesRef => {
ans: CommandBuffer.maskSamples;
maskSamplesRef: PDFileFormat.MaskSamplesRef;
loadAddress: Environment.LongNumber;
samples: LONG POINTER TO PDFileFormat.SampleArray;
words: INT;
ReadBlock[handle, @maskSamplesRef, SIZE[PDFileFormat.MaskSamplesRef]];
loadAddress.highbits ← imagingCommand.addrHighBits;
loadAddress.lowbits ← maskSamplesRef.addrLowBits;
ans.loadAddress ← loadAddress.li;
IF ans.loadAddress < 0 OR ans.loadAddress + SIZE[PDFileFormat.SampleArray] > handle.loadWords THEN BadLoadReference[SIZE[PDFileFormat.MaskSamplesRef]];
samples ← private.loadPointer + loadAddress.li;
words ← Inline.LongMult[samples.sSize, (samples.fSize+(bitsPerWord-1))/bitsPerWord];
IF ans.loadAddress + SIZE[PDFileFormat.SampleArray] + words > handle.loadWords THEN BadLoadReference[SIZE[PDFileFormat.MaskSamplesRef]];
CheckBB[handle, maskSamplesRef.sMin, maskSamplesRef.fMin, samples.sSize, samples.fSize, SIZE[PDFileFormat.Command]+SIZE[PDFileFormat.MaskSamplesRef]];
ans.samples ← [sOrigin: maskSamplesRef.sMin, fOrigin: maskSamplesRef.fMin, sMin: 0, fMin: 0, sSize: samples.sSize, fSize: samples.fSize, pointer: samples+SIZE[PDFileFormat.SampleArray], rast: (samples.fSize+(bitsPerWord-1))/bitsPerWord, lines: samples.sSize];
RETURN [ans]
};
maskRunGroupRef => {
ans: CommandBuffer.maskRunGroup;
maskRunGroupRef: PDFileFormat.MaskRunGroupRef;
loadAddress: Environment.LongNumber;
runGroup: LONG POINTER TO PDFileFormat.RunGroup;
run: LONG POINTER TO PDFileFormat.Run;
s: CARDINAL ← 0;
runCount: CARDINAL ← 0;
words: INT ← 0;
fSize: CARDINAL ← 0;
ReadBlock[handle, @maskRunGroupRef, SIZE[PDFileFormat.MaskRunGroupRef]];
loadAddress.highbits ← imagingCommand.addrHighBits;
loadAddress.lowbits ← maskRunGroupRef.addrLowBits;
ans.loadAddress ← loadAddress.li;
IF ans.loadAddress < 0 OR ans.loadAddress + SIZE[PDFileFormat.RunGroup] > handle.loadWords THEN BadLoadReference[SIZE[PDFileFormat.MaskRunGroupRef]];
runGroup ← private.loadPointer + loadAddress.li;
ans.pointer ← run ← private.loadPointer + loadAddress.li + SIZE[PDFileFormat.RunGroup];
WHILE s < runGroup.sSize DO
IF INT[run-private.loadPointer] >= handle.loadWords THEN BadLoadReference[SIZE[PDFileFormat.MaskRunGroupRef]];
IF run.fSize > fSize THEN fSize ← run.fSize;
IF run.lastRun THEN s ← s + 1;
run ← run + SIZE[PDFileFormat.Run];
ENDLOOP;
ans.runCount ← runCount;
CheckBB[handle, maskRunGroupRef.sMin, maskRunGroupRef.fMin, runGroup.sSize, fSize, SIZE[PDFileFormat.Command]+SIZE[PDFileFormat.MaskRunGroupRef]];
ans.sMin ← maskRunGroupRef.sMin;
ans.fMin ← ans.fOffset ← maskRunGroupRef.fMin;
ans.sSize ← runGroup.sSize;
ans.fSize ← fSize;
RETURN [ans]
};
maskRectangle => {
ans: CommandBuffer.maskRectangle;
maskRectangle: PDFileFormat.MaskRectangle;
ReadBlock[handle, @maskRectangle, SIZE[PDFileFormat.MaskRectangle]];
CheckBB[handle, maskRectangle.sMin, maskRectangle.fMin, maskRectangle.sSize, maskRectangle.fSize, SIZE[PDFileFormat.Command]+SIZE[PDFileFormat.MaskRectangle]];
ans.sMin ← maskRectangle.sMin;
ans.fMin ← maskRectangle.fMin;
ans.sSize ← maskRectangle.sSize;
ans.fSize ← maskRectangle.fSize;
RETURN [ans]
};
maskTrapezoid => {
ans: CommandBuffer.maskTrapezoid;
maskTrapezoid: PDFileFormat.MaskTrapezoid;
fMin, fMax: INT;
ReadBlock[handle, @maskTrapezoid, SIZE[PDFileFormat.MaskTrapezoid]];
fMin ← MIN[maskTrapezoid.fMin, maskTrapezoid.fMinLast];
fMax ← MAX[LONG[maskTrapezoid.fMin] + maskTrapezoid.fSize, LONG[maskTrapezoid.fMinLast] + maskTrapezoid.fSizeLast];
CheckBB[handle, maskTrapezoid.sMin, fMin, maskTrapezoid.sSize, fMax-fMin, SIZE[PDFileFormat.Command]+SIZE[PDFileFormat.MaskTrapezoid]];
ans.sMin ← maskTrapezoid.sMin;
ans.fMin ← maskTrapezoid.fMin;
ans.fMinLast ← maskTrapezoid.fMinLast;
ans.sSize ← maskTrapezoid.sSize;
ans.fSize ← maskTrapezoid.fSize;
ans.fSizeLast ← maskTrapezoid.fSizeLast;
RETURN [ans]
};
maskRunGroup => {
ans: CommandBuffer.maskRunGroup;
maskRunGroup: PDFileFormat.MaskRunGroup;
runGroup: PDFileFormat.RunGroup;
s: CARDINAL ← 0;
runCount: INT ← 0;
words: INT ← 0;
fMin: CARDINALLAST[CARDINAL];
fMax: CARDINALFIRST[CARDINAL];
run: LONG POINTER TO PDFileFormat.Run;
ReadBlock[handle, @maskRunGroup, SIZE[PDFileFormat.MaskRunGroup]];
ReadBlock[handle, @runGroup, SIZE[PDFileFormat.RunGroup]];
run ← private.bufferWordPointer;
WHILE s < runGroup.sSize DO
IF (runCount+1)*SIZE[PDFileFormat.Run] > private.bufferWordCount THEN {
run ← run - FillBuffer[handle, (runCount+1)*SIZE[PDFileFormat.Run]];
IF (runCount+1)*SIZE[PDFileFormat.Run] > private.bufferWordCount THEN RaisePDError[handle, runGroupTooLong, SIZE[PDFileFormat.MaskRunGroup] + SIZE[PDFileFormat.RunGroup]];
};
IF run.fMin < fMin THEN fMin ← run.fMin;
IF LONG[run.fMin] + run.fSize > fMax THEN fMax ← LONG[run.fMin] + run.fSize;
IF run.lastRun THEN s ← s + 1;
runCount ← runCount + 1;
run ← run + SIZE[PDFileFormat.Run];
ENDLOOP;
ans.runCount ← runCount;
ans.loadAddress ← -1;
IF runCount = 0 THEN {
ans.pointer ← NIL;
RaisePDWarning[handle, emptyRunGroup, SIZE[PDFileFormat.MaskRunGroup]+SIZE[PDFileFormat.RunGroup]];
fMin ← fMax;
}
ELSE {
[[ans.pointer, ----]] ← ReadLocate[handle, runCount*SIZE[PDFileFormat.Run]];
CheckBB[handle, maskRunGroup.sMin, fMin, runGroup.sSize, fMax-fMin, SIZE[PDFileFormat.Command]+SIZE[PDFileFormat.MaskRunGroupRef]]
};
ans.sMin ← maskRunGroup.sMin;
ans.fMin ← fMin;
ans.fOffset ← 0;
ans.sSize ← runGroup.sSize;
ans.fSize ← fMax;
RETURN [ans];
};
maskSamples => {
ans: CommandBuffer.maskSamples;
maskSamples: PDFileFormat.MaskSamples;
samples: PDFileFormat.SampleArray;
ReadBlock[handle, @maskSamples, SIZE[PDFileFormat.MaskSamples]];
ReadBlock[handle, @samples, SIZE[PDFileFormat.SampleArray]];
CheckBB[handle, maskSamples.sMin, maskSamples.fMin, samples.sSize, samples.fSize, SIZE[PDFileFormat.Command]+SIZE[PDFileFormat.MaskSamples]+SIZE[PDFileFormat.SampleArray]];
ans.loadAddress ← -1;
{raster: BlockDescription
← ReadLocate[
handle,
Inline.LongMult[samples.sSize, (samples.fSize+(bitsPerWord-1))/bitsPerWord]
];
ans.samples ← PDInterpBitmap.Reshape[
raster.pointer,
raster.words,
[maskSamples.sMin, maskSamples.fMin, samples.sSize, samples.fSize]
! PDInterpBitmap.InsufficientSpace => {
RaisePDError[handle, bitmapTooBig, SIZE[PDFileFormat.Command]+SIZE[PDFileFormat.MaskSamples]+SIZE[PDFileFormat.SampleArray]];
ERROR
}
];
};
RETURN [ans];
};
colorSamples => {
ans: CommandBuffer.colorSamples;
colorSamples: PDFileFormat.ColorSamples;
samples: PDFileFormat.SampleArray;
ReadBlock[handle, @colorSamples, SIZE[PDFileFormat.ColorSamples]];
ReadBlock[handle, @samples, SIZE[PDFileFormat.SampleArray]];
CheckBB[handle, colorSamples.sMin, colorSamples.fMin, samples.sSize, samples.fSize, SIZE[PDFileFormat.Command]+SIZE[PDFileFormat.ColorSamples]+SIZE[PDFileFormat.SampleArray]];
{raster: BlockDescription
← ReadLocate[
handle,
Inline.LongMult[samples.sSize, (samples.fSize+(bitsPerWord-1))/bitsPerWord]
];
ans.samples ← PDInterpBitmap.Reshape[
raster.pointer,
raster.words,
[colorSamples.sMin, colorSamples.fMin, samples.sSize, samples.fSize]
! PDInterpBitmap.InsufficientSpace => {
RaisePDError[handle, bitmapTooBig, SIZE[PDFileFormat.Command]+SIZE[PDFileFormat.MaskSamples]+SIZE[PDFileFormat.SampleArray]];
ERROR
}
];
};
RETURN [ans];
};
ENDCASE => {
RaisePDError[handle, unrecognisedImagingCommand, SIZE[PDFileFormat.Command]]; ERROR};
};
controlCommand: PDFileFormat.Command.control => {
ans: CommandBuffer.stateChange;
ans.loadChangeStart ← ans.loadChangeLength ← 0;
IF handle.colorType = none THEN SELECT controlCommand.com FROM
startImage, deviceCommand, storeLoad, endDocument => NULL;
ENDCASE => {
RaisePDError[handle, missingStartImage, SIZE[PDFileFormat.Command]];
ERROR
};
SELECT controlCommand.com FROM
startImage => {
startImage: PDFileFormat.StartImage;
ReadBlock[handle, @startImage, SIZE[PDFileFormat.StartImage]];
IF startImage.filler # 0 THEN {
RaisePDWarning[handle, nonZeroFill, SIZE[PDFileFormat.Command]+SIZE[PDFileFormat.StartImage]];
};
IF (LONG[startImage.passBands]+startImage.nBands)*handle.sSizeBand >= handle.herald.imageSSize+handle.sSizeBand
OR LONG[startImage.fMinPage]+startImage.fSizePage > handle.herald.imageFSize THEN {
RaisePDWarning[handle, imageBoundsExceedPageBounds, SIZE[PDFileFormat.Command]+SIZE[PDFileFormat.StartImage]];
};
IF handle.colorType # none AND handle.bandNumber < handle.image.nBands THEN
RaisePDWarning[handle, tooFewBands, SIZE[PDFileFormat.Command]+SIZE[PDFileFormat.StartImage]];
handle.image ← startImage;
ans.whatChanged ← imageStart;
handle.priority ← 0;
handle.colorType ← ink;
handle.bandNumber ← 0;
handle.sMinBand ← startImage.passBands*handle.sSizeBand;
IF NOT startImage.strip THEN {handle.pass ← handle.pass + 1};
IF startImage.feed THEN {handle.page ← handle.page + 1; handle.pass ← 1};
handle.status ← constructingImage;
RETURN [ans]
};
setPriority => {
priorityLow: PDFileFormat.Priority;
priority: Environment.LongNumber;
ReadBlock[handle, @priorityLow, SIZE[PDFileFormat.Priority]];
priority.highbits ← controlCommand.rest;
priority.lowbits ← priorityLow;
handle.priority ← priority.li;
ans.whatChanged ← priorityChange;
RETURN [ans]
};
setColorInk => {
handle.colorType ← ink;
ans.whatChanged ← colorChange;
RETURN [ans]
};
setColorClear => {
handle.colorType ← clear;
ans.whatChanged ← colorChange;
RETURN [ans]
};
setColorTile => {
setColorTile: PDFileFormat.SetColorTile;
ReadBlock[handle, @setColorTile, SIZE[PDFileFormat.SetColorTile]];
handle.colorTileLoadAddress ← setColorTile.addr;
SELECT controlCommand.rest FROM
0 => handle.colorType ← opaqueTile;
1 => handle.colorType ← transparentTile;
ENDCASE => {
handle.colorType ← opaqueTile;
RaisePDWarning[handle, unknownColorTileFlag, SIZE[PDFileFormat.Command]];
};
ans.whatChanged ← colorChange;
RETURN [ans];
};
endBand => {
handle.priority ← LAST[INT];
ans.whatChanged ← priorityChange;
RETURN [ans];
};
endDocument => {
ans.whatChanged ← documentEnd;
handle.status ← transmissionComplete;
WaitForClientToFindOutWeAreDone[];
RETURN [ans];
};
storeLoad => {
storeLoad: PDFileFormat.StoreLoad;
loadWordsAllocated: LONG CARDINAL ← private.loadWordsAllocated;
ReadBlock[handle, @storeLoad, SIZE[PDFileFormat.StoreLoad]];
IF storeLoad.firstAddress > loadWordsAllocated
OR storeLoad.firstAddress + storeLoad.wordCount > loadWordsAllocated
OR storeLoad.firstAddress + storeLoad.wordCount > handle.herald.maxLoadWord THEN
{RaisePDError[handle, loadOutOfBounds, SIZE[PDFileFormat.Command]+SIZE[PDFileFormat.StoreLoad]]; ERROR};
ReadBlock[handle, private.loadPointer+storeLoad.firstAddress, storeLoad.wordCount];
ans.whatChanged ← loadChange;
ans.loadChangeStart ← storeLoad.firstAddress;
ans.loadChangeLength ← storeLoad.wordCount;
handle.loadWords ← MAX[handle.loadWords, ans.loadChangeStart + ans.loadChangeLength];
handle.colorTileLoadAddress ← -1;
RETURN [ans];
};
deviceCommand => {
deviceCommand: CommandBuffer.deviceCommand;
wordCount: CARDINAL;
block: BlockDescription;
ReadBlock[handle, @wordCount, SIZE[CARDINAL]];
block ← ReadLocate[handle, wordCount];
IF block.words < wordCount THEN RaisePDError[handle, unexpectedEOF, block.words+SIZE[CARDINAL]];
deviceCommand.deviceCommandPointer ← block.pointer;
deviceCommand.deviceCommandWords ← block.words;
RETURN [deviceCommand];
};
ENDCASE => {RaisePDError[handle, unrecognisedControlCommand, SIZE[PDFileFormat.Command]]; ERROR};
};
ENDCASE => {RaisePDError[handle, unrecognisedCommandType, SIZE[PDFileFormat.Command]]; ERROR};
};
Error: PUBLIC ERROR [handle: Handle, code: PDInterpBasic.PDErrorCode, wordIndex, wordCount: INT] = CODE;
Warning: PUBLIC SIGNAL [handle: Handle, code: PDInterpBasic.PDWarningCode, wordIndex, wordCount: INT] = CODE;
RaisePDError: PROC [handle: Handle, code: PDInterpBasic.PDErrorCode, words: INT] = {
handle.status ← code;
ERROR Error[handle, code, handle.index-words, words];
};
RaisePDWarning: PROC [handle: Handle, code: PDInterpBasic.PDWarningCode, words: INT] = {
handle.warningCount ← handle.warningCount + 1;
handle.status ← code;
SIGNAL Warning[handle, code, handle.index-words, words];
};
END.