-- 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