-- AISImpl.mesa
-- Last changed by John Warnock, 23-Nov-81 16:21:11
-- Last Edited by: Stone, August 11, 1983 2:50 pm
DIRECTORY
AIS,
AISFormat,
DCSFileTypes,
Directory,
File,
Heap,
Inline,
Space,
Volume,
BitBlt,
Environment;
AISImpl: PROGRAM
IMPORTS Directory, File, Heap, Inline, Space, Volume,BitBlt
EXPORTS AIS = {OPEN AIS;
zone: UNCOUNTED ZONE = Heap.systemZone;
Error: PUBLIC SIGNAL[type: ErrorType] = CODE;
catch: BOOLEAN = TRUE;
wordsPerPage: CARDINAL = Space.wordsPerPage;
aisWordsPerPage: CARDINAL = AISFormat.aisWordsPerPage;
pagesPerAISPage: CARDINAL = aisWordsPerPage/wordsPerPage;
defaultBSize: CARDINAL ← 4*pagesPerAISPage;
bbspace: BitBlt.BBTableSpace;
bbptr: BitBlt.BBptr ← BitBlt.AlignedBBTable[@bbspace];
bbflags: BitBlt.BitBltFlags ← [direction: forward, disjoint: TRUE, disjointItems: FALSE, gray: FALSE, srcFunc: null, dstFunc: null];
ARef: TYPE = LONG POINTER TO ARep;
ARep: TYPE = RECORD [
fref: FRef ← NIL,
space: Space.Handle ← Space.nullHandle, --attributes space
header: LONG POINTER TO AISFormat.Header ← 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
];
lastARep: ARep ← [NIL,Space.Create[size: defaultBSize, parent: Space.virtualMemory],NIL,NIL,NIL,NIL];
lastARef: ARef ← @lastARep;
DivUp: PROC[n: LONG CARDINAL, d: CARDINAL] RETURNS[CARDINAL] = INLINE {
q,r: CARDINAL; [q,r] ← Inline.LongDivMod[n,d];
RETURN[IF r>0 THEN q+1 ELSE q] };
LongCopy: PROC[from: LONG POINTER, to: LONG POINTER, nwords: LONG CARDINAL] = INLINE {
wpb: CARDINAL ← 177777B;
q,r: CARDINAL; [q,r] ← Inline.LongDivMod[num: nwords,den: wpb];
FOR i: CARDINAL IN [0..q) DO
Inline.LongCOPY[from: from, to: to, nwords: wpb];
from ← from+wpb;
ENDLOOP;
Inline.LongCOPY[from: from, to: to, nwords: r];
};
CreateFile: PUBLIC PROC[name: LONG STRING, raster: Raster,
overwrite: BOOLEAN, attributeLength: CARDINAL] RETURNS[f: FRef] = {
file: File.Capability ← File.nullCapability;
filesize: File.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: File.PageNumber; -- starting file pages
-- Check for reasonable parameters
SELECT raster.bitsPerPixel FROM
0 => { bpp ← 1; ppw ← 16 };
1,2,4,8,16 => { bpp ← raster.bitsPerPixel; ppw ← 16/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 ← 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 ← Inline.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 ← Inline.LongMult[wpl,lines];
rpages ← DivUp[rwords,aisWordsPerPage] --total ais pages in raster part
};
abase ← 1; -- attributes follow leader page
rbase ← abase + pagesPerAISPage*apages;
filesize ← rbase + pagesPerAISPage*rpages;
IF overwrite THEN Directory.DeleteFile[fileName: name !
Directory.Error => SELECT type FROM
fileNotFound => CONTINUE;
invalidFileName => IF catch THEN GOTO BadName;
ENDCASE;
];
file ← Directory.CreateFile[fileName: name,
fileType: DCSFileTypes.tLeaderPage, size: filesize !
Directory.Error => SELECT type FROM
fileAlreadyExists => IF catch THEN GOTO OldFile;
invalidFileName => IF catch THEN GOTO BadName;
ENDCASE;
Volume.InsufficientSpace => IF catch THEN GOTO NoRoom;
];
file ← File.LimitPermissions[file, File.read + File.write];
f ← zone.NEW[FRep ← [file: file, write: TRUE, abase: abase, rbase: rbase, raster: raster, wordsPerLine: wpl, buffersize: 0]];
IF raster.linesPerBlock>0 THEN f.buffersize ← bpages*pagesPerAISPage ELSE SetBufferSize[f];
IF lastARef.fref#NIL THEN DeleteLastARef[];
lastARef.fref ← f;
lastARef.header ← zone.NEW[AISFormat.Header ← [password: AISFormat.aisPassword, attributeLength: attributeLength]];
Space.Map[space: lastARef.space, window: [file: f.file, base: abase]];
lastARef.raster ← zone.NEW[uca AISFormat.RasterPart ← [
part: AISFormat.PartHeader[type: raster, length: SIZE[uca AISFormat.RasterPart]],
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];
EXITS
BadName => Error[invalidFileName];
OldFile => Error[fileAlreadyExists];
NoRoom => Error[volumeFull];
};
DeleteFile: PUBLIC PROC[name: LONG STRING] RETURNS[success: BOOLEAN] = {
success ← TRUE;
Directory.DeleteFile[name !
Directory.Error => SELECT type FROM
fileNotFound => { success ← FALSE; CONTINUE };
ENDCASE];
RETURN[success];
};
OpenFile: PUBLIC PROC[name: LONG STRING, write: BOOLEAN ← FALSE] RETURNS[f: FRef] = {
file: File.Capability ← Directory.Lookup[
fileName: name,
permissions: (IF write THEN File.read + File.write ELSE File.read)
! Directory.Error =>SELECT type FROM
fileNotFound => IF catch THEN GOTO NotFound;
invalidFileName => IF catch THEN GOTO BadName;
ENDCASE;
];
scanmode: ScanMode ← ru;
apages: Space.PageCount;
f ← zone.NEW[FRep];
f.file ← file;
f.abase ← FirstPage[f.file];
ReadAttributes[f]; --sets up lastARef, and maps the file
apages ← lastARef.header.attributeLength/wordsPerPage;
f.rbase ← f.abase + apages;
scanmode ← SELECT lastARef.raster.scanDir FROM
2 => ru,
3 => rd,
6 => lu,
7 => ld,
9 => ul,
8 => ur,
13 => dl,
12 => dr,
ENDCASE => rd;
f.raster ← zone.NEW[AIS.RasterPart ←
[scanCount: lastARef.raster.scanCount, scanLength: lastARef.raster.scanLength,
scanMode: scanmode, bitsPerPixel: lastARef.raster.bitsPerSample,
linesPerBlock: lastARef.raster.scanLinesPerBlock, paddingPerBlock: lastARef.raster.paddingPerBlock]];
f.wordsPerLine ← lastARef.raster.wordsPerScanLine;
f.write ← write;
IF lastARef.raster.scanLinesPerBlock>0 THEN {
bwords: LONG CARDINAL ←
Inline.LongMult[lastARef.raster.wordsPerScanLine,lastARef.raster.scanLinesPerBlock];
bpages: LONG CARDINAL ← DivUp[bwords,aisWordsPerPage]; -- ais pages per block
temp: LONG CARDINAL ← bpages*pagesPerAISPage;
IF Inline.HighHalf[temp]=0 THEN f.buffersize ← Inline.LowHalf[temp] ELSE ERROR;
}
ELSE SetBufferSize[f];
RETURN[f];
EXITS
BadName => Error[invalidFileName];
NotFound => Error[fileNotFound];
};
CloseFile: PUBLIC PROC[f: FRef] = {
--If the file is mapped, writes out the file and cleans up the local data structures
IF f=lastARef.fref THEN DeleteLastARef[];
zone.FREE[@f]; --dangle, dangle...
};
SetBufferSize: PROC[f: FRef] = {
rsize: CARDINAL ← DivUp[Inline.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, s: LONG STRING] RETURNS[BOOLEAN] = {
len: INTEGER;
ReadAttributes[f];
IF lastARef.comment=NIL THEN RETURN[FALSE];
len ← LOOPHOLE[lastARef.comment.chars[0]];
len ← MIN[s.length, len];
IF len<=0 THEN RETURN[FALSE];
FOR i: INTEGER IN [0..len) DO s[i] ← lastARef.comment.chars[i+1]; ENDLOOP;
RETURN[TRUE];
};
WriteComment: PUBLIC PROC[f: FRef, s: LONG STRING] = {
len: CARDINAL ← s.length;
ReadAttributes[f];
IF ~f.write THEN Error[readOnlyFile];
len ← MIN[256,len];
IF lastARef.comment#NIL THEN zone.FREE[@lastARef.comment];
lastARef.comment ← zone.NEW[AISFormat.CommentPart[len+1]];
lastARef.comment.part ← [type: comment, length: SIZE[AISFormat.CommentPart[len+1]]];
lastARef.comment.chars[0] ← LOOPHOLE[len];
FOR i: CARDINAL IN [0..len) DO lastARef.comment.chars[i+1] ← s[i]; ENDLOOP;
};
ReadPlacement: PUBLIC PROC[f: FRef, placement: Placement] RETURNS[BOOLEAN] = {
ReadAttributes[f];
IF lastARef.placement=NIL THEN RETURN[FALSE];
placement↑ ← [
xLeft: lastARef.placement.xLeft,
yBottom: lastARef.placement.yBottom,
xWidth: lastARef.placement.xWidth,
yHeight: lastARef.placement.yHeight];
RETURN[TRUE];
};
WritePlacement: PUBLIC PROC[f: FRef, placement: Placement] = {
ReadAttributes[f];
IF ~f.write THEN Error[readOnlyFile];
IF lastARef.placement=NIL THEN lastARef.placement ← zone.NEW[AISFormat.PlacementPart];
lastARef.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, raster: Raster] = {
ReadAttributes[f];
IF lastARef.fref.raster=NIL THEN ERROR;
raster↑ ← f.raster↑;
};
ReadPhotometry: PUBLIC PROC[f: FRef, photometry: Photometry] RETURNS[BOOLEAN] = {
ReadAttributes[f];
IF lastARef.photometry=NIL THEN RETURN[FALSE];
photometry↑ ← [
signal: lastARef.photometry.signal,
sense: lastARef.photometry.sense,
scaleType: lastARef.photometry.scaleType,
pointA: lastARef.photometry.pointA,
pointB: lastARef.photometry.pointB,
pointC: lastARef.photometry.pointC,
spotType: lastARef.photometry.spotType,
spotWidth: lastARef.photometry.spotWidth,
spotLength: lastARef.photometry.spotLength,
sampleMin: lastARef.photometry.sampleMin,
sampleMax: lastARef.photometry.sampleMax,
histogramLength: lastARef.photometry.histogramLength];
RETURN[TRUE];
};
ReadHistogram: PUBLIC PROC[f: FRef, histogram: Histogram] RETURNS[BOOLEAN] = {
l: INTEGER;
ReadAttributes[f];
IF lastARef.photometry=NIL OR lastARef.photometry.histogramLength<=0 THEN RETURN[FALSE];
l ← MIN[lastARef.photometry.histogramLength,histogram.len];
FOR i: INTEGER IN [0..l) DO
histogram[i] ← lastARef.photometry.histogram[i];
ENDLOOP;
RETURN[TRUE];
};
WritePhotometry: PUBLIC PROC[f: FRef, photometry: Photometry, histogram: Histogram ← NIL] = {
len: INTEGER ← 0;
ReadAttributes[f];
IF ~f.write THEN Error[readOnlyFile];
--Error check the lengths
IF histogram#NIL THEN {len ← histogram.len; IF len#photometry.histogramLength THEN ERROR}
ELSE IF photometry.histogramLength>0 THEN ERROR;
--allocate the lastARef fields according to the length
IF lastARef.photometry#NIL THEN zone.FREE[@lastARef.photometry];
lastARef.photometry ← zone.NEW[AISFormat.PhotometryPart[len]];
lastARef.photometry.part ← [type: photometry, length: SIZE[AISFormat.PhotometryPart[len]]];
lastARef.photometry.signal ← photometry.signal;
lastARef.photometry.sense ← photometry.sense;
lastARef.photometry.scaleType ← photometry.scaleType;
lastARef.photometry.pointA ← photometry.pointA;
lastARef.photometry.pointB ← photometry.pointB;
lastARef.photometry.pointC ← photometry.pointC;
lastARef.photometry.spotType ← photometry.spotType;
lastARef.photometry.spotWidth ← photometry.spotWidth;
lastARef.photometry.spotLength ← photometry.spotLength;
lastARef.photometry.sampleMin ← photometry.sampleMin;
lastARef.photometry.sampleMax ← photometry.sampleMax;
lastARef.photometry.histogramLength ← photometry.histogramLength;
IF histogram#NIL THEN FOR i: INTEGER IN [0..len] DO
lastARef.photometry.histogram[i] ← histogram[i];
ENDLOOP;
};
-- Window operations --
OpenWindow: PUBLIC PROC[f: FRef,
firstScan: CARDINAL ← 0, lastScan: CARDINAL ← LAST[CARDINAL],
firstPixel: CARDINAL ← 0, lastPixel: CARDINAL ← LAST[CARDINAL]]
RETURNS[w: WRef] = {
bref: BRef;
wpl,ppw: CARDINAL;
bref ← zone.NEW[BRep];
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↑ ← [space: Space.Create[f.buffersize,Space.virtualMemory],
addr: NIL, first: 0, last: 0];
ppw ← IF f.raster.bitsPerPixel=0 THEN 16 ELSE 16/f.raster.bitsPerPixel;
wpl ← DivUp[lastPixel-firstPixel+1,ppw];
w ← zone.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] = {
Space.Delete[w.bref.space];
zone.FREE[@w.bref];
zone.FREE[@w]; --dangle, dangle
};
--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] THEN RETURN; --already mapped in
GMBuff[w,scan];};
GMBuff:PROC [w: WRef, scan: CARDINAL ← 0] =
{page,offset,lnum,loff: CARDINAL;
--compute which file page
[page,offset] ← Inline.LongDivMod[num: Inline.LongMult[scan,w.fref.wordsPerLine], den: wordsPerPage];
IF w.bref.addr#NIL THEN Space.Unmap[w.bref.space]; --first time, isn't mapped
Space.Map[w.bref.space,[w.fref.file,w.fref.rbase+page]];
--compute the number of the first scanline in the buffer
[lnum,loff] ← Inline.LongDivMod[num: offset, den: w.fref.wordsPerLine];
w.bref.addr ← Space.LongPointer[w.bref.space]+loff;
w.bref.first ← scan-lnum;
w.bref.last ← w.bref.first + Inline.LongDiv[num: Inline.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)]};
--Buffer: TYPE = LONG DESCRIPTOR FOR ARRAY OF WORD;
ReadLine: PUBLIC PROC[w: WRef, buffer: Buffer, line: INTEGER ← -1] = {
XFerLine[w,buffer,line,TRUE];
};
WriteLine: PUBLIC PROC[w: WRef, buffer: Buffer, line: INTEGER ← -1] = {
XFerLine[w,buffer,line,FALSE];
};
XFerLine: PROC[w: WRef, buffer: Buffer, line: INTEGER ← -1, read: BOOLEAN] = {
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] ← Inline.LongDivMod[num:w.firstPixel,den: w.pixelsPerWord];
word ← w.bref.addr+Inline.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: BitBlt.BitAddress;
bit: CARDINAL ← IF w.fref.raster.bitsPerPixel=0 THEN poff ELSE poff*w.fref.raster.bitsPerPixel;
bufferwidth: CARDINAL ← w.wordsPerLine*16;
filebpl: CARDINAL ← w.fref.wordsPerLine*16;
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];
};
BitBlt.BITBLT[bbptr];
};
w.nextScanLine ← MIN[line+1,w.lastScan];
};
ReadLines: PUBLIC PROC[w: WRef, buffer: Buffer, line: INTEGER ← -1, count: CARDINAL ← 1]
RETURNS[numberRead: CARDINAL] = {
RETURN[XFerLines[w,buffer,line,count,TRUE]];
};
WriteLines: PUBLIC PROC[w: WRef, buffer: Buffer, line: INTEGER ← -1, count: CARDINAL ← 1]
RETURNS[numberWritten: CARDINAL] = {
RETURN[XFerLines[w,buffer,line,count,FALSE]];
};
XFerLines: PROC[w: WRef, buffer: Buffer, line: INTEGER ← -1, count: CARDINAL ← 1, read: BOOLEAN]
RETURNS[numberRead: CARDINAL] = {
temp: LONG CARDINAL;
maxline: LONG CARDINAL ← 0;
numberRead ← 0;
temp←Inline.LongMult[w.wordsPerLine,count];
IF buffer.addr=NIL OR temp>buffer.length THEN Error[bufferTooSmall];
IF line=-1 THEN line ← w.nextScanLine;
IF CARDINAL[line]+w.firstScan > w.lastScan THEN Error[outOfRange];
maxline ← w.firstScan+(buffer.length/w.wordsPerLine)-1;
IF w.wordsPerLine=w.fref.wordsPerLine THEN {
first: CARDINAL ← line+w.firstScan;
lastscan,last: CARDINAL ← first+count-1;
to: LONG POINTER ← buffer.addr;
from: LONG POINTER ← NIL;
nlines,nwords: CARDINAL ← 0;
lastscan ← MIN[lastscan,w.lastScan];
IF lastscan>maxline THEN Error[bufferTooSmall];
UNTIL numberRead>= count DO
MapBuffer[w,first];
last ← MIN[lastscan,w.bref.last];
nlines ← last-first+1;
nwords ← nlines*w.wordsPerLine;
from ← w.bref.addr+Inline.LongMult[(first-w.bref.first),w.wordsPerLine];
IF read THEN LongCopy[from: from, to: to, nwords: nwords]
ELSE LongCopy[from: to, to: from, nwords: nwords];
numberRead ← numberRead+nlines;
first ← last+1;
to ← to+nwords;
ENDLOOP;
}
ELSE {
tbuffer: Buffer ← [w.wordsPerLine, Heap.MakeNode[zone, w.wordsPerLine]];
to: LONG POINTER ← buffer.addr;
tbuffer.length ← w.wordsPerLine;
FOR i: CARDINAL IN[0..count) DO
IF CARDINAL[line]+w.firstScan>maxline THEN Error[bufferTooSmall];
IF read THEN {
ReadLine[w,tbuffer,line ! Error => IF type=outOfRange THEN EXIT ELSE ERROR];
LongCopy[from: tbuffer.addr, to: to, nwords: tbuffer.length];
}
ELSE {
LongCopy[from: to, to: tbuffer.addr, nwords: tbuffer.length];
WriteLine[w,tbuffer,line ! Error => IF type=outOfRange THEN EXIT ELSE ERROR];
};
line ← line+1;
to ← to+w.wordsPerLine;
numberRead ← numberRead+1;
ENDLOOP;
};
w.nextScanLine ← MIN[line+numberRead,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] = {
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←absline;
w.clineaddr ← w.bref.addr+Inline.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] = {
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←absline;
w.clineaddr ← w.bref.addr+Inline.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];
};
ReadAttributes: PROC[f:FRef] = {OPEN AISFormat;
addr: LONG POINTER ← NIL; -- address of first word of attributes
words: CARDINAL ← 0; -- number of words read from attributes
awords: CARDINAL ← apages*Environment.wordsPerPage;
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;
string: LONG STRING ← NIL;
apages: Space.PageCount;
IF lastARef.fref#NIL THEN
IF f.file = lastARef.fref.file THEN RETURN --we just did the read
ELSE DeleteLastARef[];
lastARef.fref ← f;
Space.Map[space: lastARef.space, window: [file: f.file, base: f.abase]];
addr ← Space.LongPointer[lastARef.space];
header ← addr;
IF header.password#AISFormat.aisPassword THEN Error[invalidFile]; -- wrong password
IF (header.attributeLength MOD AISFormat.aisWordsPerPage)=0 THEN {
apages ← header.attributeLength/wordsPerPage;
IF apages > Space.GetAttributes[lastARef.space].size THEN {
Space.Delete[lastARef.space];
lastARef.space ← Space.Create[size: apages, parent: Space.virtualMemory];
Space.Map[space: lastARef.space, window: [file: f.file, base: f.abase]];
};
}
ELSE Error[invalidFile]; -- illegal attribute length
lastARef.header ← zone.NEW[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]; lastARef.raster ← zone.NEW[uca RasterPart ← raster↑]}
ELSE Error[invalidFile]; -- multiple raster parts
placement => IF placement=NIL
THEN {placement ← LOOPHOLE[part]; lastARef.placement ← zone.NEW[PlacementPart ← placement↑]}
ELSE Error[invalidFile]; -- multiple placement parts
photometry => IF photometry=NIL THEN {
hlen: INTEGER;
photometry ← LOOPHOLE[part];
hlen ← photometry.histogramLength;
IF hlen<0 THEN hlen ← 0;
lastARef.photometry ← zone.NEW[PhotometryPart[hlen] ← photometry↑];
}
ELSE Error[invalidFile]; -- multiple photometry parts
comment => IF comment=NIL
THEN {comment ← LOOPHOLE[part]; lastARef.comment ← zone.NEW[CommentPart ← comment↑]}
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
};
FirstPage: PROC[file: File.Capability] RETURNS[File.PageNumber] = {
RETURN[1]; --should check with the Directory stuff
};
DeleteLastARef: PROC = {OPEN lastARef; --using: fref,header,space,raster,placement,photometry,comment
IF fref=NIL THEN ERROR;
IF fref.write THEN WriteLastARef[];
--don't free the FRef. Someone has a hold of it!
IF header#NIL THEN {zone.FREE[@header]; header ← NIL};
IF raster#NIL THEN {zone.FREE[@raster]; raster ← NIL};
IF placement#NIL THEN {zone.FREE[@placement]; placement ← NIL};
IF photometry#NIL THEN {zone.FREE[@photometry]; photometry ← NIL};
IF comment#NIL THEN {zone.FREE[@comment]; comment ← NIL};
Space.Unmap[space];
lastARef.fref ← NIL;
};
WriteLastARef: PROC = {OPEN Inline,lastARef; --using: header,space,raster,placement,photometry,comment
--assumes the file is mapped to lastARef.space
--if all elements are NIL, this is a NOOP
to: LONG POINTER ← Space.LongPointer[space];
IF header#NIL THEN
{LongCOPY[from: header, to: to, nwords: SIZE[AISFormat.Header]]; to ← to+SIZE[AISFormat.Header]};
IF raster#NIL THEN
{LongCOPY[from: raster, to: to, nwords: raster.part.length]; to ← to+raster.part.length};
IF placement#NIL THEN
{LongCOPY[from: placement, to: to, nwords: placement.part.length]; to ← to+placement.part.length};
IF photometry#NIL THEN
{LongCOPY[from: photometry, to: to, nwords: photometry.part.length]; to ← to+photometry.part.length};
IF comment#NIL THEN
{LongCOPY[from: comment, to: to, nwords: comment.part.length]; to ← to+raster.part.length};
};
-- Initialization
bbptr↑ ← [dst: [word: NIL,bit:0], dstBpl: 0, src: [word: NIL,bit: 0], srcDesc: [srcBpl[srcBpl: 0]], width: 0, height: 0, flags: bbflags]
}.
-- 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