PDFileReaderImpl.mesa
Michael Plass, April 6, 1984 1:03:55 pm PST
Last Edited by: Pier, December 13, 1983 3:47 pm
DIRECTORY
Basics, CountedVM, FS, IO, PDFileFormat, Rope, ImagerPixelMaps, PDFileReader, SafeStorage;
PDFileReaderImpl: CEDAR PROGRAM
IMPORTS Basics, CountedVM, FS, IO, ImagerPixelMaps, SafeStorage
EXPORTS PDFileReader
~ BEGIN OPEN PDFileReader;
bitsPerWord: NAT ~ Basics.bitsPerWord;
RawStreamOptions: PROC RETURNS [options: FS.StreamOptions ← FS.defaultStreamOptions] ~ INLINE {options[tiogaRead] ← FALSE};
Private: TYPE ~ REF PrivateRep;
PrivateRep: TYPE ~ RECORD [
maskRectangle: MaskRectangle ← NIL,
maskTrapezoid: MaskTrapezoid ← NIL,
maskRunGroup: MaskRunGroup ← NIL,
maskSamples: MaskSamples ← NIL,
colorSamples: ColorSamples ← NIL,
stateChange: StateChange ← NIL,
loadStorage: CountedVM.Handle,
tempRefRep: REF ImagerPixelMaps.PixelMapRep -- temp for building tiles
];
ColorTileFromLoad: PUBLIC PROC [handle: Handle, colorTileLoadAddress: INT, scratch: REF ImagerPixelMaps.PixelMapRep] RETURNS [colorTile: ImagerPixelMaps.Tile] ~ TRUSTED {
private: Private ← NARROW[handle.private];
pixelMap: ImagerPixelMaps.PixelMap ← [0,0,0,0,0,0,private.tempRefRep];
words: INT;
tile: LONG POINTER TO PDFileFormat.Tile;
IF colorTileLoadAddress < 0 OR colorTileLoadAddress > handle.loadWords OR colorTileLoadAddress + SIZE[PDFileFormat.Tile] > handle.loadWords THEN RaisePDError[handle, badLoadReference, 0];
tile ← private.loadStorage.Pointer + colorTileLoadAddress;
words ← Basics.LongMult[tile.sSize, (tile.fSize+(bitsPerWord-1))/bitsPerWord];
IF colorTileLoadAddress + SIZE[PDFileFormat.Tile] + words > handle.loadWords THEN RaisePDError[handle, badLoadReference, 0];
pixelMap.sOrigin ← tile.sMin;
pixelMap.fOrigin ← tile.fMin;
pixelMap.sSize ← tile.sSize;
pixelMap.fSize ← tile.fSize;
pixelMap.refRep.pointer ← private.loadStorage.Pointer + colorTileLoadAddress + SIZE[PDFileFormat.Tile];
pixelMap.refRep.words ← words;
pixelMap.refRep.rast ← (tile.fSize+(bitsPerWord-1))/bitsPerWord;
pixelMap.refRep.lines ← tile.sSize;
colorTile ← ImagerPixelMaps.CreateTile[pixelMap, tile.phase, 100, scratch];
};
Open: PUBLIC PROC [fileName: ROPE] RETURNS [Handle] ~ {
stream: IO.STREAMFS.StreamOpen[fileName: fileName, streamOptions: RawStreamOptions[]];
RETURN [FromStream[stream]];
};
FromStream: PUBLIC PROC [stream: IO.STREAM] RETURNS [handle: Handle] ~ {
private: Private ← NEW[PrivateRep];
handle ← NEW[Rep];
handle.private ← private;
handle.stream ← stream;
handle.colorType ← none;
handle.colorTileLoadAddress ← -1;
handle.priority ← 0;
handle.warningCount ← 0;
ReadHerald[handle];
AllocateLoadSpace[handle];
private.tempRefRep ← NEW[ImagerPixelMaps.PixelMapRep ← [
ref: private.loadStorage,
pointer: NIL,
words: 0,
lgBitsPerPixel: 0,
rast: 0,
lines: 0
]];
};
ReadHerald: PROC [handle: Handle] ~ TRUSTED {
herald: PDFileFormat.Herald;
ReadBlock[handle, @herald, SIZE[PDFileFormat.Herald]];
IF herald.password # PDFileFormat.passwordValue THEN {
RaisePDError[handle, invalidPassword, SIZE[PDFileFormat.Herald]];
};
IF herald.version # PDFileFormat.versionValue THEN {
RaisePDWarning[handle, wrongFormatVersion, SIZE[PDFileFormat.Herald]];
};
IF NOT (herald.sResolution IN [10..10000])
OR NOT (herald.fResolution IN [10..10000]) THEN {
RaisePDWarning[handle, unreasonableResolution, SIZE[PDFileFormat.Herald]];
};
IF NOT (herald.bandSSize IN [8..32767]) THEN {
RaisePDWarning[handle, unreasonableBandSSize, SIZE[PDFileFormat.Herald]];
};
IF NOT (herald.imageSSize IN [80..32767])
OR NOT (herald.imageFSize IN [80..32767]) THEN {
RaisePDWarning[handle, unreasonableImageSize, SIZE[PDFileFormat.Herald]];
};
IF herald.maxLoadWord > 60000 THEN {
RaisePDWarning[handle, unreasonableLoadSize, SIZE[PDFileFormat.Herald]];
};
IF NOT (herald.copies IN [1..200]) THEN {
RaisePDWarning[handle, unreasonableNumberOfCopies, SIZE[PDFileFormat.Herald]];
};
handle.herald ← herald;
handle.sSizeBand ← herald.bandSSize;
};
AllocateLoadSpace: PROC [handle: Handle] ~ {
private: Private ← NARROW[handle.private];
IF handle.herald.maxLoadWord > 0 THEN private.loadStorage ← CountedVM.Allocate[handle.herald.maxLoadWord];
};
Close: PUBLIC PROC [handle: Handle] ~ {
IF handle.stream # NIL THEN {IO.Close[handle.stream]; handle.stream←NIL};
IF handle.private # NIL THEN {
private: Private ← NARROW[handle.private];
private.tempRefRep.ref ← NIL;
private.tempRefRep ← NIL;
private.loadStorage ← NIL;
handle.private ← NIL;
};
SafeStorage.ReclaimCollectibleObjects[];
};
ReadBlock: UNSAFE PROC [handle: Handle, dest: LONG POINTER, words: CARDINAL] ~ UNCHECKED {
bytes: INT ← words*Basics.bytesPerWord;
bytesRead: INT ← 0;
bytesRead ← IO.UnsafeGetBlock[handle.stream, [dest, 0, bytes]];
IF bytesRead < bytes THEN RaisePDError[handle, unexpectedEOF, bytesRead/2];
};
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, scanning: BOOLEANFALSE] RETURNS [REF] ~ TRUSTED {
private: Private ← NARROW[handle.private];
command: PDFileFormat.Command;
BadLoadReference: PROC [dataWords: INT] ~ CHECKED {
RaisePDError[handle, badLoadReference, SIZE[PDFileFormat.Command]+dataWords];
};
IF handle.priority = LAST[INT] THEN {
ans: StateChange ← IF private.stateChange # NIL THEN private.stateChange ELSE (private.stateChange←NEW[StateChangeRep]);
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;
};
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: MaskSamples ← IF private.maskSamples # NIL THEN private.maskSamples ELSE (private.maskSamples←NEW[MaskSamplesRep]);
maskSamplesRef: PDFileFormat.MaskSamplesRef;
loadAddress: Basics.LongNumber;
samples: LONG POINTER TO PDFileFormat.SampleArray;
words: INT;
refRep: REF ImagerPixelMaps.PixelMapRep ←
IF ans.samples.refRep = NIL THEN NEW[ImagerPixelMaps.PixelMapRep ← [
ref: private.loadStorage,
pointer: NIL,
words: 0,
rast: 0,
lines: 0,
lgBitsPerPixel: 0
]]
ELSE ans.samples.refRep;
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.loadStorage.Pointer + loadAddress.li;
words ← Basics.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]];
refRep.pointer ← samples+SIZE[PDFileFormat.SampleArray];
refRep.words ← words;
refRep.rast ← (samples.fSize+(bitsPerWord-1))/bitsPerWord;
refRep.lines ← samples.sSize;
ans.samples ← [sOrigin: maskSamplesRef.sMin, fOrigin: maskSamplesRef.fMin, sMin: 0, fMin: 0, sSize: samples.sSize, fSize: samples.fSize, refRep: refRep];
RETURN [ans];
};
maskRunGroupRef => {
ans: MaskRunGroup ← IF private.maskRunGroup # NIL THEN private.maskRunGroup ELSE (private.maskRunGroup←NEW[MaskRunGroupRep]);
maskRunGroupRef: PDFileFormat.MaskRunGroupRef;
loadAddress: Basics.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.ref ← private.loadStorage;
ans.loadAddress ← loadAddress.li;
IF ans.loadAddress < 0 OR ans.loadAddress + SIZE[PDFileFormat.RunGroup] > handle.loadWords THEN BadLoadReference[SIZE[PDFileFormat.MaskRunGroupRef]];
runGroup ← private.loadStorage.Pointer + loadAddress.li;
ans.pointer ← run ← private.loadStorage.Pointer + loadAddress.li + SIZE[PDFileFormat.RunGroup];
WHILE s < runGroup.sSize DO
IF INT[run-private.loadStorage.Pointer] >= handle.loadWords THEN BadLoadReference[SIZE[PDFileFormat.MaskRunGroupRef]];
IF LONG[run.fMin] + run.fSize > fSize THEN fSize ← LONG[run.fMin] + run.fSize;
IF run.lastRun THEN s ← s + 1;
run ← run + SIZE[PDFileFormat.Run];
runCount ← runCount + 1;
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: MaskRectangle ← IF private.maskRectangle # NIL THEN private.maskRectangle ELSE (private.maskRectangle←NEW[MaskRectangleRep]);
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: MaskTrapezoid ← IF private.maskTrapezoid # NIL THEN private.maskTrapezoid ELSE (private.maskTrapezoid←NEW[MaskTrapezoidRep]);
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: MaskRunGroup ← IF private.maskRunGroup # NIL THEN private.maskRunGroup ELSE (private.maskRunGroup←NEW[MaskRunGroupRep]);
maskRunGroup: PDFileFormat.MaskRunGroup;
runGroup: PDFileFormat.RunGroup;
run: PDFileFormat.Run;
s: CARDINAL ← 0;
runCount: INT ← 0;
words: INT ← 0;
fMin: CARDINALLAST[CARDINAL];
fMax: CARDINALFIRST[CARDINAL];
runGroupStart: INT;
ReadBlock[handle, @maskRunGroup, SIZE[PDFileFormat.MaskRunGroup]];
ReadBlock[handle, @runGroup, SIZE[PDFileFormat.RunGroup]];
runGroupStart ← IO.GetIndex[handle.stream];
WHILE s < runGroup.sSize DO
ReadBlock[handle, @run, SIZE[PDFileFormat.Run]];
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;
ENDLOOP;
ans.runCount ← runCount;
ans.loadAddress ← -1;
IF runCount = 0 THEN {
ans.pointer ← NIL;
ans.ref ← NIL;
RaisePDWarning[handle, emptyRunGroup, SIZE[PDFileFormat.MaskRunGroup]+SIZE[PDFileFormat.RunGroup]];
fMin ← fMax;
}
ELSE IF scanning THEN {
ans.pointer ← NIL;
ans.ref ← NIL;
}
ELSE {
storage: DeviceCommand ← NEW[DeviceCommandRep[runCount*SIZE[PDFileFormat.Run]]];
handle.stream.SetIndex[runGroupStart];
ans.ref ← storage;
ans.pointer ← LOOPHOLE[@(storage[0])];
ReadBlock[handle, ans.pointer, storage.wordCount];
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: MaskSamples ← IF private.maskSamples # NIL THEN private.maskSamples ELSE (private.maskSamples←NEW[MaskSamplesRep]);
maskSamples: PDFileFormat.MaskSamples;
samples: PDFileFormat.SampleArray;
words: LONG CARDINAL;
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]];
words ← Basics.LongMult[samples.sSize, (samples.fSize+(bitsPerWord-1))/bitsPerWord];
ans.loadAddress ← -1;
IF scanning THEN {
handle.stream.SetIndex[handle.stream.GetIndex[]+words*Basics.bytesPerWord]
}
ELSE {
ans.samples ← ImagerPixelMaps.Create[0, [maskSamples.sMin, maskSamples.fMin, samples.sSize, samples.fSize]];
IF ans.samples.refRep.words # words THEN ERROR;
ReadBlock[handle, ans.samples.refRep.pointer, words];
};
RETURN [ans];
};
colorSamples => {
ans: ColorSamples ← IF private.colorSamples # NIL THEN private.colorSamples ELSE (private.colorSamples←NEW[ColorSamplesRep]);
colorSamples: PDFileFormat.ColorSamples;
samples: PDFileFormat.SampleArray;
words: LONG CARDINAL;
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]];
words ← Basics.LongMult[samples.sSize, (samples.fSize+(bitsPerWord-1))/bitsPerWord];
IF scanning THEN{
handle.stream.SetIndex[handle.stream.GetIndex[]+words*Basics.bytesPerWord]
}
ELSE {
ans.samples ← ImagerPixelMaps.Create[0, [colorSamples.sMin, colorSamples.fMin, samples.sSize, samples.fSize]];
IF ans.samples.refRep.words # words THEN ERROR;
ReadBlock[handle, ans.samples.refRep.pointer, words]
};
RETURN [ans];
};
ENDCASE => {
RaisePDError[handle, unrecognisedImagingCommand, SIZE[PDFileFormat.Command]]; ERROR};
};
controlCommand: PDFileFormat.Command.control => {
ans: StateChange ← IF private.stateChange # NIL THEN private.stateChange ELSE (private.stateChange←NEW[StateChangeRep]);
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;
RETURN [ans]
};
setPriority => {
priorityLow: PDFileFormat.Priority;
priority: Basics.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 => {
tile: LONG POINTER TO PDFileFormat.Tile;
words: INT;
setColorTile: PDFileFormat.SetColorTile;
ReadBlock[handle, @setColorTile, SIZE[PDFileFormat.SetColorTile]];
handle.colorTileLoadAddress ← setColorTile.addr;
IF handle.colorTileLoadAddress < 0 OR handle.colorTileLoadAddress > handle.loadWords OR handle.colorTileLoadAddress + SIZE[PDFileFormat.Tile] > handle.loadWords THEN BadLoadReference[SIZE[PDFileFormat.SetColorTile]];
tile ← private.loadStorage.Pointer + setColorTile.addr;
words ← Basics.LongMult[tile.sSize, (tile.fSize+(bitsPerWord-1))/bitsPerWord];
IF INT[setColorTile.addr] + SIZE[PDFileFormat.Tile] + words > handle.loadWords THEN BadLoadReference[SIZE[PDFileFormat.SetColorTile]];
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;
RETURN [ans];
};
storeLoad => {
storeLoad: PDFileFormat.StoreLoad;
ReadBlock[handle, @storeLoad, SIZE[PDFileFormat.StoreLoad]];
IF storeLoad.firstAddress > LAST[LONG CARDINAL]/256
OR storeLoad.firstAddress + storeLoad.wordCount > handle.herald.maxLoadWord THEN
{RaisePDError[handle, loadOutOfBounds, SIZE[PDFileFormat.Command]+SIZE[PDFileFormat.StoreLoad]]; ERROR};
ReadBlock[handle, private.loadStorage.Pointer+storeLoad.firstAddress, storeLoad.wordCount];
ans.whatChanged ← loadChange;
ans.loadChangeStart ← storeLoad.firstAddress;
ans.loadChangeLength ← storeLoad.wordCount;
handle.loadWords ← MAX[handle.loadWords, ans.loadChangeStart + ans.loadChangeLength];
RETURN [ans];
};
deviceCommand => {
deviceCommand: DeviceCommand;
wordCount: CARDINAL;
ReadBlock[handle, @wordCount, SIZE[CARDINAL]];
deviceCommand ← NEW[DeviceCommandRep[wordCount]];
IF wordCount > 0 THEN {
ReadBlock[handle, @(deviceCommand[0]), wordCount];
};
RETURN [deviceCommand];
};
ENDCASE => {RaisePDError[handle, unrecognisedControlCommand, SIZE[PDFileFormat.Command]]; ERROR};
};
ENDCASE => {RaisePDError[handle, unrecognisedCommandType, SIZE[PDFileFormat.Command]]; ERROR};
};
Keep: PUBLIC PROC [handle: Handle, ref: REF] RETURNS [REF] ~ {
private: Private ← NARROW[handle.private];
SELECT ref FROM
private.maskRectangle => private.maskRectangle ← NIL;
private.maskTrapezoid => private.maskTrapezoid ← NIL;
private.maskRunGroup => private.maskRunGroup ← NIL;
private.maskSamples => private.maskSamples ← NIL;
private.colorSamples => private.colorSamples ← NIL;
private.stateChange => private.stateChange ← NIL;
ENDCASE => NULL;
RETURN [ref]
};
Error: PUBLIC ERROR
[handle: Handle, code: ErrorCode, wordIndex, wordCount: INT, description: ROPE] ~ CODE;
Warning: PUBLIC SIGNAL
[handle: Handle, code: ErrorCode, wordIndex, wordCount: INT, description: ROPE] ~ CODE;
RaisePDError: PROC [handle: Handle, code: ErrorCode, words: INT] ~ {
index: INTIO.GetIndex[handle.stream];
wordIndex: INT ← index/Basics.bytesPerWord - words;
IO.SetIndex[handle.stream, wordIndex*Basics.bytesPerWord];
ERROR Error[handle, code, wordIndex, words, descriptionFor[code]];
};
RaisePDWarning: PROC [handle: Handle, code: ErrorCode, words: INT] ~ {
index: INTIO.GetIndex[handle.stream];
wordIndex: INT ← index/Basics.bytesPerWord - words;
IO.SetIndex[handle.stream, wordIndex*Basics.bytesPerWord];
handle.warningCount ← handle.warningCount + 1;
SIGNAL Warning[handle, code, wordIndex, words, descriptionFor[code]];
IO.SetIndex[handle.stream, index];
};
descriptionFor: ARRAY ErrorCode OF ROPE ~ [
invalidPassword: "Invalid PD file password",
objectOutOfBounds: "Object exceeds page boundaries",
missingStartImage: "This command must be in the scope of a StartImage command",
badLoadReference: "Reference to load exceeds load bounds",
unrecognisedImagingCommand: "Unrecognised imaging command",
loadOutOfBounds: "Attempt to exceed load size declared in herald",
unrecognisedControlCommand: "Unrecognised control command",
unrecognisedCommandType: "Unrecognised command type",
unexpectedEOF: "Unexpected end of file",
wrongFormatVersion: "The version of the PD file format does not match the software version",
unreasonableResolution: "The resolution is not in a reasonable range",
unreasonableBandSSize: "The band size is not in a reasonable range",
unreasonableImageSize: "The image size is not in a reasonable range",
unreasonableLoadSize: "The load size is not in a reasonable range",
unreasonableNumberOfCopies: "The requested number of copies is not in a reasonable range",
objectOutOfBand: "Object does not touch band in which it is used",
emptyRunGroup: "Run group has zero runs",
nonZeroFill: "Fill bits in startImage command are non-zero",
imageBoundsExceedPageBounds: "Image bounds in startImage command exceed page boundaries",
tooFewBands: "Too few bands in image",
unknownColorTileFlag: "Unknown flag byte in setColorTile command"
];
END.