AISImpl.mesa
Last changed by John Warnock, 23-Nov-81 16:21:11
Last Edited by: Stone, August 11, 1983 2:50 pm
Last changed by Michael Plass, December 27, 1983 11:20 am
DIRECTORY
AIS,
AISFormat,
Basics,
CountedVM,
FS,
IO,
PrincOps,
Rope,
PrincOpsUtils,
SafeStorage,
VM;
AISImpl: CEDAR PROGRAM
IMPORTS FS, IO, CountedVM, PrincOpsUtils, Basics, SafeStorage, Rope, VM
EXPORTS AIS = {OPEN AIS;
Error: PUBLIC SIGNAL [type: ErrorType] = CODE;
catch: BOOLEAN = TRUE;
wordsPerPage: CARDINAL = PrincOps.wordsPerPage;
bitsPerWord: CARDINAL = Basics.bitsPerWord;
aisWordsPerPage: CARDINAL = AISFormat.aisWordsPerPage;
pagesPerAISPage: CARDINAL = aisWordsPerPage/wordsPerPage;
defaultBSize: CARDINAL ← 4*pagesPerAISPage;
bbflags: PrincOps.BitBltFlags ~ [direction: forward, disjoint: TRUE, disjointItems: FALSE, gray: FALSE, srcFunc: null, dstFunc: null];
DivUp: PROC [n: LONG CARDINAL, d: CARDINAL] RETURNS [CARDINAL] = INLINE {
q, r: CARDINAL; [q,r] ← Basics.LongDivMod[n,d];
RETURN[IF r>0 THEN q+1 ELSE q]
};
LongCopy: UNSAFE PROC [from: LONG POINTER, to: LONG POINTER, nwords: LONG CARDINAL] = UNCHECKED INLINE {
wpb: CARDINAL ← 177777B;
q,r: CARDINAL; [q, r] ← Basics.LongDivMod[num: nwords, den: wpb];
FOR i: CARDINAL IN [0..q) DO
PrincOpsUtils.LongCopy[from: from, to: to, nwords: wpb];
from ← from+wpb;
ENDLOOP;
PrincOpsUtils.LongCopy[from: from, to: to, nwords: r];
};
CreateFile: PUBLIC PROC [name: ROPE, raster: Raster, attributeLength: CARDINAL] RETURNS [f: FRef] = {
file: FS.OpenFile ← FS.nullOpenFile;
filesize: PrincOps.PageCount ← 0;
bpp: CARDINAL ← 0; -- bits per pixel
ppw: CARDINAL ← 0; -- pixels per word
wpl: CARDINAL ← 0; -- words per scan line
lines: CARDINAL ← 0; -- raster.scanLength
pixels: CARDINAL ← 0; -- raster.scanCount
apages, rpages, bpages: CARDINAL ← 0; -- AIS pages in attribute, raster, and block
abase, rbase: VM.PageNumber; -- starting file pages
aRef: ARef ← NEW[ARep];
Check for reasonable parameters
SELECT raster.bitsPerPixel FROM
0 => { bpp ← 1; ppw ← bitsPerWord };
1,2,4,8,16 => { bpp ← raster.bitsPerPixel; ppw ← bitsPerWord/bpp };
3,5,6,7,IN[9..15] => Error[notImplemented]; -- not expected
ENDCASE => Error[invalidParameter]; -- 0 or out of range
IF raster.scanCount>0 AND raster.scanLength>0 THEN {
lines ← raster.scanCount;
pixels ← raster.scanLength;
wpl ← DivUp[pixels,ppw];
}
ELSE Error[invalidParameter]; -- bad scanCount or scanLength
apages ← (IF attributeLength=0 THEN 1
ELSE DivUp[attributeLength, aisWordsPerPage]);
attributeLength ← LONG[aisWordsPerPage]*apages;
compute the number of pages to hold the raster
IF raster.linesPerBlock>0 THEN {
blocks: CARDINAL ← DivUp[lines, raster.linesPerBlock]; -- number of blocks
bwords: LONG CARDINAL ← Basics.LongMult[wpl, raster.linesPerBlock];
bpages ← DivUp[bwords, aisWordsPerPage]; -- ais pages per block
rpages ← blocks*bpages; --total ais pages in raster part
}
ELSE {
rwords: LONG CARDINAL ← Basics.LongMult[wpl, lines];
rpages ← DivUp[rwords, aisWordsPerPage] --total ais pages in raster part
};
abase ← 0;
rbase ← abase + pagesPerAISPage*apages;
filesize ← rbase + pagesPerAISPage*rpages;
file ← FS.Create[name: name, pages: filesize];
FS.SetByteCountAndCreatedTime[file: file, bytes: FS.BytesForPages[filesize]];
f ← NEW[FRep ← [file: file, write: TRUE, abase: abase, rbase: rbase, raster: raster, attributes: aRef, wordsPerLine: wpl, buffersize: 0]];
IF raster.linesPerBlock>0 THEN f.buffersize ← bpages*pagesPerAISPage ELSE SetBufferSize[f];
aRef.header ← NEW[AISFormat.Header ← [password: AISFormat.aisPassword, attributeLength: attributeLength]];
aRef.raster ← NEW[AISFormat.RasterPart.uca ← [
part: AISFormat.PartHeader[type: raster, length: SIZE[AISFormat.RasterPart.uca]],
scanCount: raster.scanCount, scanLength: raster.scanLength,
scanDir: (SELECT raster.scanMode FROM
ru => 2,
rd => 3,
lu => 6,
ld => 7,
ul => 9,
ur => 8,
dl => 13,
dr => 12,
ENDCASE => ERROR),
samplesPerPixel: 1,
coding: uca[bitsPerSample: raster.bitsPerPixel, wordsPerScanLine: wpl,
scanLinesPerBlock: raster.linesPerBlock, paddingPerBlock: raster.paddingPerBlock]
]];
RETURN[f];
};
DeleteFile: PUBLIC PROC [name: ROPE] = {
FS.Delete[name];
};
OpenFile: PUBLIC PROC[name: ROPE, write: BOOLEANFALSE] RETURNS [f: FRef] = {
file: FS.OpenFile ← FS.Open[
name: name,
lock: IF write THEN $write ELSE $read
];
scanmode: ScanMode ← ru;
apages: PrincOps.PageCount;
f ← NEW[FRep];
f.file ← file;
f.abase ← 0;
ReadAttributes[f]; --sets up f.attributes
apages ← f.attributes.header.attributeLength/wordsPerPage;
f.rbase ← f.abase + apages;
scanmode ← SELECT f.attributes.raster.scanDir FROM
2 => ru,
3 => rd,
6 => lu,
7 => ld,
9 => ul,
8 => ur,
13 => dl,
12 => dr,
ENDCASE => rd;
f.raster ← NEW[AIS.RasterPart ←
[scanCount: f.attributes.raster.scanCount, scanLength: f.attributes.raster.scanLength,
scanMode: scanmode, bitsPerPixel: f.attributes.raster.bitsPerSample,
linesPerBlock: f.attributes.raster.scanLinesPerBlock, paddingPerBlock: f.attributes.raster.paddingPerBlock]];
f.wordsPerLine ← f.attributes.raster.wordsPerScanLine;
f.write ← write;
IF f.attributes.raster.scanLinesPerBlock>0 THEN {
bwords: LONG CARDINAL
Basics.LongMult[f.attributes.raster.wordsPerScanLine, f.attributes.raster.scanLinesPerBlock];
bpages: LONG CARDINAL ← DivUp[bwords,aisWordsPerPage]; -- ais pages per block
temp: LONG CARDINAL ← bpages*pagesPerAISPage;
IF Basics.HighHalf[temp]=0 THEN f.buffersize ← Basics.LowHalf[temp] ELSE ERROR;
}
ELSE SetBufferSize[f];
RETURN[f];
};
CloseFile: PUBLIC PROC [f: FRef] = {
attributesTruncated: BOOLEANFALSE;
IF f.write THEN attributesTruncated ← FlushBuffersAndClose[f];
IF attributesTruncated THEN Error[attributesTooLong]
};
SetBufferSize: PROC [f: FRef] = {
rsize: CARDINAL ← DivUp[Basics.LongMult[f.wordsPerLine, f.raster.scanCount], wordsPerPage];
f.buffersize ← IF rsize < defaultBSize THEN rsize ELSE defaultBSize;
};
read and write the attribute parts
ReadComment: PUBLIC PROC [f: FRef] RETURNS [ROPE] = {
IF f.attributes.comment = NIL THEN RETURN [NIL]
ELSE {
chars: NAT ~ ORD[f.attributes.comment[0]];
words: NAT ~ f.attributes.comment.part.length - SIZE[AISFormat.PartHeader];
text: REF TEXTNEW[TEXT[chars]];
IF chars+1 > words*Basics.bytesPerWord THEN Error[invalidParameter];
FOR i: NAT IN [0..chars) DO
text[i] ← f.attributes.comment[i+1];
ENDLOOP;
text.length ← chars;
RETURN [Rope.FromRefText[text]]
};
};
WriteComment: PUBLIC PROC [f: FRef, comment: ROPE] = {
length: [0..256) ← Rope.Length[comment];
IF ~f.write THEN Error[readOnlyFile];
f.attributes.comment ← NEW[AISFormat.CommentPart[length+1]];
f.attributes.comment.part ← [type: comment, length: SIZE[AISFormat.CommentPart[length+1]]];
f.attributes.comment[0] ← VAL[length];
FOR i: NAT IN [0..length) DO
f.attributes.comment[i+1] ← comment.Fetch[i];
ENDLOOP;
};
ReadPlacement: PUBLIC PROC [f: FRef] RETURNS [Placement] = {
IF f.attributes.placement = NIL THEN RETURN [NIL];
RETURN [NEW[PlacementPart ← [
xLeft: f.attributes.placement.xLeft,
yBottom: f.attributes.placement.yBottom,
xWidth: f.attributes.placement.xWidth,
yHeight: f.attributes.placement.yHeight
]]];
};
WritePlacement: PUBLIC PROC [f: FRef, placement: Placement] = {
IF ~f.write THEN Error[readOnlyFile];
IF placement = NIL THEN f.attributes.placement ← NIL
ELSE {
IF f.attributes.placement=NIL THEN f.attributes.placement ← NEW[AISFormat.PlacementPart];
f.attributes.placement^ ← [
part: [type: placement, length: SIZE[AISFormat.PlacementPart]],
xLeft: placement.xLeft,
yBottom: placement.yBottom,
xWidth: placement.xWidth,
yHeight: placement.yHeight
];
};
};
ReadRaster: PUBLIC PROC [f: FRef] RETURNS [Raster] = {
RETURN [NEW[RasterPart ← f.raster^]];
};
ReadPhotometry: PUBLIC PROC [f: FRef] RETURNS [photometry: Photometry] = {
IF f.attributes.photometry=NIL THEN RETURN [NIL];
RETURN[NEW[PhotometryPart ← [
signal: f.attributes.photometry.signal,
sense: f.attributes.photometry.sense,
scaleType: f.attributes.photometry.scaleType,
pointA: f.attributes.photometry.pointA,
pointB: f.attributes.photometry.pointB,
pointC: f.attributes.photometry.pointC,
spotType: f.attributes.photometry.spotType,
spotWidth: f.attributes.photometry.spotWidth,
spotLength: f.attributes.photometry.spotLength,
sampleMin: f.attributes.photometry.sampleMin,
sampleMax: f.attributes.photometry.sampleMax,
histogramLength: f.attributes.photometry.histogramLength
]]];
};
ReadHistogram: PUBLIC PROC [f: FRef] RETURNS [histogram: Histogram] = {
IF f.attributes.photometry=NIL OR f.attributes.photometry.histogramLength<=0 THEN RETURN [NIL];
histogram ← NEW[HistogramRep[f.attributes.photometry.histogramLength]];
FOR i: NAT IN [0..histogram.length) DO
histogram[i] ← f.attributes.photometry.histogram[i];
ENDLOOP;
};
WritePhotometry: PUBLIC PROC [f: FRef, photometry: Photometry, histogram: Histogram ← NIL] = {
histogramLength: INTEGER ← 0;
p: REF AISFormat.PhotometryPart ← NIL;
IF ~f.write THEN Error[readOnlyFile];
IF photometry = NIL AND histogram = NIL THEN {f.attributes.photometry ← NIL; RETURN};
Error check the lengths
IF histogram#NIL THEN histogramLength ← histogram.length;
IF histogramLength # photometry.histogramLength THEN ERROR;
p ← NEW[AISFormat.PhotometryPart[histogramLength]];
p.part ← [type: photometry, length: SIZE[AISFormat.PhotometryPart[histogramLength]]];
p.signal ← photometry.signal;
p.sense ← photometry.sense;
p.scaleType ← photometry.scaleType;
p.pointA ← photometry.pointA;
p.pointB ← photometry.pointB;
p.pointC ← photometry.pointC;
p.spotType ← photometry.spotType;
p.spotWidth ← photometry.spotWidth;
p.spotLength ← photometry.spotLength;
p.sampleMin ← photometry.sampleMin;
p.sampleMax ← photometry.sampleMax;
p.histogramLength ← photometry.histogramLength;
FOR i: INTEGER IN [0..histogramLength) DO
p[i] ← histogram[i];
ENDLOOP;
f.attributes.photometry ← p;
};
Window operations --
OpenWindow: PUBLIC PROC [f: FRef,
firstScan: CARDINAL ← 0, lastScan: CARDINALLAST[CARDINAL],
firstPixel: CARDINAL ← 0, lastPixel: CARDINALLAST[CARDINAL]]
RETURNS [w: WRef] = {
bref: BRef ← NEW[BRep];
wpl, ppw: CARDINAL;
IF lastScan=LAST[CARDINAL] THEN lastScan ← f.raster.scanCount;
IF lastPixel=LAST[CARDINAL] THEN lastPixel ← f.raster.scanLength;
lastScan ← MIN[f.raster.scanCount-1,lastScan];
lastPixel ← MIN[f.raster.scanLength-1,lastPixel];
IF firstScan>lastScan THEN Error[badWindow];
IF firstPixel>lastPixel THEN Error[badWindow];
bref^ ← [countedVM: CountedVM.Allocate[VM.WordsForPages[f.buffersize]], addr: NIL, first: 0, last: 0, firstPage: 0, nPages: 0];
ppw ← IF f.raster.bitsPerPixel=0 THEN bitsPerWord ELSE bitsPerWord/f.raster.bitsPerPixel;
wpl ← DivUp[lastPixel-firstPixel+1,ppw];
w ← NEW[WRep ← [fref: f, bref: bref,
firstScan: firstScan, lastScan: lastScan, firstPixel: firstPixel, lastPixel: lastPixel,
wordsPerLine: wpl, pixelsPerWord: ppw]];
MapBuffer[w, w.firstScan];
};
CloseWindow: PUBLIC PROC [w: WRef] = {
w.fref ← NIL;
w.bref ← NIL;
SafeStorage.ReclaimCollectibleObjects[];
};
scan is absolute scan number
MapBuffer: PROC [w: WRef, scan: CARDINAL ← 0] = INLINE {
IF scan>w.lastScan THEN Error[outOfRange];
IF w.bref.addr#NIL AND scan IN [w.bref.first..w.bref.last]
AND (w.fref.outputBuffer = NIL OR w.fref.outputBuffer = w.bref) THEN RETURN; --already mapped in
GMBuff[w, scan];
};
GMBuff: PROC [w: WRef, scan: CARDINAL ← 0] = TRUSTED {
page, offset, lnum, loff: CARDINAL;
IF w.fref.outputBuffer # NIL THEN {
FS.Write[
file: w.fref.file,
to: w.fref.outputBuffer.firstPage,
nPages: w.fref.outputBuffer.nPages,
from: CountedVM.Pointer[w.fref.outputBuffer.countedVM]
];
w.fref.outputBuffer ← NIL;
};
compute which file page
[page, offset] ← Basics.LongDivMod[num: Basics.LongMult[scan, w.fref.wordsPerLine], den: wordsPerPage];
w.bref.firstPage ← w.fref.rbase+page;
w.bref.nPages ← MIN[w.bref.countedVM.interval.count, MAX[FS.GetInfo[w.fref.file].pages-(w.fref.rbase+page), 0]];
FS.Read[
file: w.fref.file,
from: w.bref.firstPage,
nPages: w.bref.nPages,
to: CountedVM.Pointer[w.bref.countedVM]
];
compute the number of the first scanline in the buffer
[lnum,loff] ← Basics.LongDivMod[num: offset, den: w.fref.wordsPerLine];
w.bref.addr ← CountedVM.Pointer[w.bref.countedVM]+loff;
w.bref.first ← scan-lnum;
w.bref.last ← w.bref.first + Basics.LongDiv[num: Basics.LongMult[w.fref.buffersize, wordsPerPage]-loff, den: w.fref.wordsPerLine] - 1;
};
GetWindowParams: PUBLIC PROC [w: WRef]
RETURNS [firstScan: CARDINAL, lastScan: CARDINAL, firstPixel: CARDINAL, lastPixel: CARDINAL] = {
firstScan ← w.firstScan;
lastScan ← w.lastScan;
firstPixel ← w.firstPixel;
lastPixel ← w.lastPixel;
}; 
MinBufferSize: PUBLIC PROC [w: WRef] RETURNS [length: CARDINAL] = {RETURN[w.wordsPerLine]};
EndOfWindow: PUBLIC PROC [w: WRef] RETURNS [BOOLEAN] = {RETURN[w.nextScanLine=(w.lastScan-w.firstScan)]};
UnsafeReadLine: PUBLIC UNSAFE PROC [w: WRef, buffer: Buffer, line: INTEGER ← -1] = UNCHECKED {
XFerLine[w,buffer,line,TRUE];
};
UnsafeWriteLine: PUBLIC UNSAFE PROC [w: WRef, buffer: Buffer, line: INTEGER ← -1] = UNCHECKED {
IF NOT w.fref.write THEN Error[readOnlyFile];
XFerLine[w,buffer,line,FALSE];
w.fref.outputBuffer ← w.bref;
};
XFerLine: UNSAFE PROC [w: WRef, buffer: Buffer, line: INTEGER ← -1, read: BOOLEAN] = UNCHECKED {
woff, poff, absline: CARDINAL;
word: LONG POINTER;
IF w.wordsPerLine > buffer.length THEN Error[bufferTooSmall];
IF line=-1 THEN line ← w.nextScanLine;
absline ← CARDINAL[line]+w.firstScan;
IF absline > w.lastScan THEN Error[outOfRange];
MapBuffer[w, absline];
[woff,poff] ← Basics.LongDivMod[num: w.firstPixel, den: w.pixelsPerWord];
word ← w.bref.addr+Basics.LongMult[w.fref.wordsPerLine, (absline-w.bref.first)]+woff;
IF poff=0 THEN {
IF read THEN LongCopy[from: word, to: buffer.addr, nwords: w.wordsPerLine]
ELSE LongCopy[from: buffer.addr, to: word, nwords: w.wordsPerLine]
}
ELSE {
src, dst: PrincOps.BitAddress;
bit: CARDINALIF w.fref.raster.bitsPerPixel=0 THEN poff ELSE poff*w.fref.raster.bitsPerPixel;
bufferwidth: CARDINAL ← w.wordsPerLine*bitsPerWord;
filebpl: CARDINAL ← w.fref.wordsPerLine*bitsPerWord;
bbspace: PrincOps.BBTableSpace;
bbptr: PrincOps.BBptr ← PrincOpsUtils.AlignedBBTable[@bbspace];
IF read THEN {
src ← [word: word, bit: bit];
dst ← [word: buffer.addr, bit: 0];
bbptr^ ← [dst: dst, dstBpl: bufferwidth, src: src, srcDesc: [srcBpl[srcBpl: filebpl]],
width: bufferwidth, height: 1, flags: bbflags];
}
ELSE {
dst ← [word: word, bit: bit];
src ← [word: buffer.addr, bit: 0];
bbptr^ ← [dst: dst, dstBpl: filebpl, src: src, srcDesc: [srcBpl[srcBpl: bufferwidth]],
width: bufferwidth, height: 1, flags: bbflags];
};
PrincOpsUtils.BITBLT[bbptr];
};
w.nextScanLine ← MIN[line+1,w.lastScan];
};
Line1: TYPE = RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF [0..1B]];
Line2: TYPE = RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF [0..3B]];
Line4: TYPE = RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF [0..17B]];
Line8: TYPE = RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF [0..377B]];
Line16: TYPE = RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF WORD];
ReadSample: PUBLIC PROC [w: WRef, line, pixel: CARDINAL] RETURNS [value: CARDINAL] = TRUSTED {
lineaddr: LONG POINTER;
absline: CARDINAL ← line+w.firstScan;
IF absline # w.currline THEN {
IF absline > w.lastScan THEN Error[outOfRange];
MapBuffer[w, absline];
w.currline�sline;
w.clineaddr ← w.bref.addr+Basics.LongMult[(absline-w.bref.first),w.fref.wordsPerLine];
}
ELSE {IF pixel+ w.firstPixel > w.lastPixel THEN Error[outOfRange]};
lineaddr←w.clineaddr;
SELECT w.fref.raster.bitsPerPixel FROM
0,1 => RETURN[LOOPHOLE[lineaddr,LONG POINTER TO Line1][pixel]];
2 => RETURN[LOOPHOLE[lineaddr,LONG POINTER TO Line2][pixel]];
4 => RETURN[LOOPHOLE[lineaddr,LONG POINTER TO Line4][pixel]];
8 => RETURN[LOOPHOLE[lineaddr,LONG POINTER TO Line8][pixel]];
16 => RETURN[LOOPHOLE[lineaddr,LONG POINTER TO Line16][pixel]];
ENDCASE => Error[notImplemented];
w.nextScanLine ← MIN[line+1,w.lastScan];
};
WriteSample: PUBLIC PROC [w: WRef, value: CARDINAL, line, pixel: CARDINAL] = TRUSTED {
lineaddr: LONG POINTER;
absline: CARDINAL ← line+w.firstScan;
IF NOT w.fref.write THEN Error[readOnlyFile];
IF absline # w.currline THEN {
IF absline > w.lastScan THEN Error[outOfRange];
MapBuffer[w, absline];
w.currline ← absline;
w.clineaddr ← w.bref.addr+Basics.LongMult[(absline-w.bref.first),w.fref.wordsPerLine];
}
ELSE {IF pixel+ w.firstPixel > w.lastPixel THEN Error[outOfRange]};
lineaddr←w.clineaddr;
SELECT w.fref.raster.bitsPerPixel FROM
0,1 => LOOPHOLE[lineaddr,LONG POINTER TO Line1][pixel] ← value;
2 => LOOPHOLE[lineaddr,LONG POINTER TO Line2][pixel] ← value;
4 => LOOPHOLE[lineaddr,LONG POINTER TO Line4][pixel] ← value;
8 => LOOPHOLE[lineaddr,LONG POINTER TO Line8][pixel] ← value;
16 => LOOPHOLE[lineaddr,LONG POINTER TO Line16][pixel] ← value;
ENDCASE => Error[notImplemented];
w.nextScanLine ← MIN[line+1,w.lastScan];
w.fref.outputBuffer ← w.bref;
};
ReadAttributes: PROC [f: FRef] = TRUSTED {
addr: LONG POINTERNIL; -- address of first word of attributes
words: LONG CARDINAL ← 0; -- number of words read from attributes
header: LONG POINTER TO AISFormat.Header ← NIL;
part: LONG POINTER TO AISFormat.PartHeader ← NIL;
raster: LONG POINTER TO uca AISFormat.RasterPart ← NIL;
placement: LONG POINTER TO AISFormat.PlacementPart ← NIL;
photometry: LONG POINTER TO AISFormat.PhotometryPart ← NIL;
comment: LONG POINTER TO AISFormat.CommentPart ← NIL;
space: CountedVM.Handle ← CountedVM.Allocate[AISFormat.aisWordsPerPage];
attributes: ARef ← NEW[ARep];
f.attributes ← attributes;
FS.Read[
file: f.file,
from: 0,
nPages: space.interval.count,
to: CountedVM.Pointer[space]
];
header ← CountedVM.Pointer[space];
IF header.password#AISFormat.aisPassword THEN Error[invalidFile]; -- wrong password
IF header.attributeLength > CountedVM.Words[space] THEN {
header ← NIL;
space ← CountedVM.Allocate[header.attributeLength];
FS.Read[
file: f.file,
from: 0,
nPages: space.interval.count,
to: CountedVM.Pointer[space]
];
};
addr ← CountedVM.Pointer[space];
header ← addr;
IF header.password#AISFormat.aisPassword THEN Error[invalidFile]; -- wrong password
IF (header.attributeLength MOD wordsPerPage) # 0 THEN Error[invalidFile]; -- illegal attribute length
attributes.header ← NEW[AISFormat.Header ← header^];
words ← SIZE[AISFormat.Header];
DO -- read the parts
part ← addr + words; words ← words + part.length;
IF words>header.attributeLength THEN
Error[invalidFile]; -- part overflows end of attribute section
SELECT part.type FROM
nil => EXIT; -- no more parts
raster => IF raster=NIL
THEN {raster ← LOOPHOLE[part]; attributes.raster ← NEW[AISFormat.RasterPart.uca ← raster^]}
ELSE Error[invalidFile]; -- multiple raster parts
placement => IF placement=NIL
THEN {placement ← LOOPHOLE[part]; attributes.placement ← NEW[AISFormat.PlacementPart ← placement^]}
ELSE Error[invalidFile]; -- multiple placement parts
photometry => {
IF photometry=NIL THEN {
hlen: INTEGER ← 0;
words: NAT ← 0;
photometry ← LOOPHOLE[part];
hlen ← photometry.histogramLength;
IF hlen<0 THEN hlen ← 0;
words ← SIZE[AISFormat.PhotometryPart[hlen]];
IF words > photometry.part.length THEN Error[invalidFile];
attributes.photometry ← NEW[AISFormat.PhotometryPart[hlen]];
PrincOpsUtils.LongCopy[from: photometry, to: LOOPHOLE[attributes.photometry], nwords: words];
}
ELSE Error[invalidFile]; -- multiple photometry parts
};
comment => {
IF comment=NIL THEN {
words: NAT ← 0;
comment ← LOOPHOLE[part];
words ← SIZE[AISFormat.CommentPart[ORD[comment[0]+1]]];
IF comment.part.length < words THEN Error[invalidFile];
attributes.comment ← NEW[AISFormat.CommentPart[ORD[comment[0]+1]]];
PrincOpsUtils.LongCopy[from: comment, to: LOOPHOLE[attributes.comment], nwords: words];
}
ELSE Error[invalidFile]; -- multiple comment parts
};
ENDCASE => Error[invalidFile]; -- unknown part type
ENDLOOP;
IF raster=NIL THEN Error[invalidFile]; -- raster part missing
IF raster.samplesPerPixel#1 THEN ERROR; -- Can't handle multiple samples per pixel
IF raster.codingType#uca THEN ERROR; -- Coding type not UCA
space ← NIL;
SafeStorage.ReclaimCollectibleObjects[];
};
FlushBuffersAndClose: PROC [f: FRef] RETURNS [truncated: BOOLEANFALSE] = TRUSTED {
stream: IO.STREAMNIL;
wordsWritten: INT ← 0;
zero: CARDINAL ← 0;
WriteBlock: UNSAFE PROC [addr: LONG POINTER, words: NAT] ~ UNCHECKED {
IF wordsWritten + words > f.attributes.header.attributeLength THEN truncated ← TRUE
ELSE {
IO.UnsafePutBlock[stream, [base: addr, startIndex: 0, count: Basics.bytesPerWord*words]];
wordsWritten ← wordsWritten + words;
};
};
IF f.outputBuffer # NIL THEN {
FS.Write[
file: f.file,
to: f.outputBuffer.firstPage,
nPages: f.outputBuffer.nPages,
from: CountedVM.Pointer[f.outputBuffer.countedVM]
];
f.outputBuffer ← NIL;
};
stream ← FS.StreamFromOpenFile[f.file, $write];
WriteBlock[LOOPHOLE[f.attributes.header], SIZE[AISFormat.Header]];
IF f.attributes.raster#NIL THEN
WriteBlock[LOOPHOLE[f.attributes.raster], f.attributes.raster.part.length];
IF f.attributes.placement # NIL THEN
WriteBlock[LOOPHOLE[f.attributes.placement], f.attributes.placement.part.length];
IF f.attributes.photometry # NIL THEN
WriteBlock[LOOPHOLE[f.attributes.photometry], f.attributes.photometry.part.length];
IF f.attributes.comment#NIL THEN
WriteBlock[LOOPHOLE[f.attributes.comment], f.attributes.comment.part.length];
WriteBlock[@zero, SIZE[CARDINAL]];
IO.Close[stream];
};
}.
Last changed by Maureen Stone, 17-Nov-81 17:32:46 fixed overwrite in CreateFile
Last changed by Maureen Stone, 17-Nov-81 13:59:17 fixed write header in DeleteLastARef, and changed linesPerBlock in CreateFile
Last changed by Gordon Hamachi, 5-Nov-81 18:47:08, to fix overflow on first check in XferLines
Last changed by Gordon Hamachi, 5-Nov-81 18:38:18, to fix the computation of rsize in SetBufferSize
Last changed by Maureen Stone, 5-Nov-81 17:26:28
Last changed by John Warnock, 23-Nov-81 16:20:02, changed MapBuffer,ReadSample, and WriteSample
Last changed by Michael Plass, December 22, 1983 10:58 am, Cedar 5.0 conversion.