DIRECTORY AISFileFormat USING [AttributeHeader, byteSizeAttributeHeader, byteSizeCommentPart, byteSizePartHeader, byteSizePhotometryPart, byteSizePlacementPart, byteSizeRasterPart, byteSizeUCACoding, bytesPerAISWord, CommentPart, nil, PartHeader, passwordValue, PhotometryPart, PlacementPart, RasterPart, UCACoding, wordsPerAISPage], Basics USING [BITSHIFT, bitsPerByte, LongMult], FS USING [StreamOpen], IIPixelArray USING [Error, Join3, PixelArray], IIPixelArrayAISPrivate USING [Data, DataRep], IIPixelArrayPrivate USING [GetSamplesProc, MaxSampleValueProc, New, NewClass, PixelArrayClass], IISample USING [GetBase, GetSamples, GetSize, NewSampleMap, SampleMap], IITransformation USING [ScanMode, SFToXY, Transformation], IO USING [EndOfStream, GetIndex, SetIndex, STREAM, UnsafeGetBlock], Rope USING [FromProc, ROPE], SF USING [Vec]; IIPixelArrayAISImpl: CEDAR MONITOR LOCKS data USING data: Data IMPORTS Basics, FS, IIPixelArray, IIPixelArrayPrivate, IISample, IITransformation, IO, Rope EXPORTS IIPixelArray ~ BEGIN ROPE: TYPE ~ Rope.ROPE; STREAM: TYPE ~ IO.STREAM; PixelArray: TYPE ~ IIPixelArray.PixelArray; Data: TYPE ~ IIPixelArrayAISPrivate.Data; DataRep: TYPE ~ IIPixelArrayAISPrivate.DataRep; defaultLinesPerBlock: NAT _ 16; ProduceError: PROC [explanation: ROPE] ~ { ERROR IIPixelArray.Error[[code: $invalidAISFile, explanation: explanation]]; }; Assert: PROC [assertion: BOOL] ~ { IF NOT assertion THEN ProduceError["AIS file structure is inconsistent."]; }; BytesForAISWords: PROC [aisWords: CARDINAL] RETURNS [INT] ~ INLINE { RETURN[Basics.LongMult[AISFileFormat.bytesPerAISWord, aisWords]]; }; ReadBytes: UNSAFE PROC [stream: STREAM, base: LONG POINTER, bytes: INT] ~ UNCHECKED { actualBytes: INT ~ IO.UnsafeGetBlock[stream, [base: LOOPHOLE[base], count: bytes]]; IF actualBytes#bytes THEN ERROR IO.EndOfStream[stream]; -- file too short }; FromAIS: PUBLIC PROC [name: ROPE] RETURNS [PixelArray] ~ { OPEN AISFileFormat; stream: STREAM ~ FS.StreamOpen[name]; data: Data ~ NEW[DataRep _ [stream: stream]]; header: AttributeHeader; m: IITransformation.Transformation _ NIL; -- from [s, f] to [x, y] TRUSTED { ReadBytes[stream, @header, byteSizeAttributeHeader] }; IF header.password#passwordValue THEN ProduceError["AIS password value is wrong."]; Assert[header.length>0 AND (header.length MOD wordsPerAISPage)=0]; data.rasterSectionIndex _ BytesForAISWords[header.length]; FOR firstPart: BOOL _ TRUE, FALSE DO partHeader: PartHeader; startIndex: INT ~ IO.GetIndex[stream]; stopIndex: INT; TRUSTED { ReadBytes[stream, @partHeader, byteSizePartHeader] }; stopIndex _ startIndex+BytesForAISWords[partHeader.length]; Assert[stopIndex<=data.rasterSectionIndex]; SELECT partHeader.type FROM nil => { Assert[partHeader.length=0]; EXIT }; -- should be a zero word raster => { raster: RasterPart; Assert[firstPart]; -- raster part must be first TRUSTED { ReadBytes[stream, @raster, byteSizeRasterPart] }; Assert[IO.GetIndex[stream]<=stopIndex]; Assert[raster.scanCount>0 AND raster.scanLength>0 AND raster.samplesPerPixel>0]; data.raster _ NEW[RasterPart _ raster]; SELECT raster.codingType FROM uca => { uca: UCACoding; byteSizeCoding: INT ~ stopIndex-IO.GetIndex[stream]; Assert[byteSizeCoding<=byteSizeUCACoding]; TRUSTED { ReadBytes[stream, @uca, byteSizeCoding] }; IF uca.bitsPerSample=0 THEN uca.bitsPerSample _ 1; -- kludge Assert[INT[uca.bitsPerSample]*INT[raster.samplesPerPixel]*INT[raster.scanLength] <=INT[Basics.bitsPerByte]*BytesForAISWords[uca.wordsPerScanLine]]; IF byteSizeCoding ProduceError["Unknown AIS coding type."]; }; placement => { placement: PlacementPart; TRUSTED { ReadBytes[stream, @placement, byteSizePlacementPart] }; Assert[IO.GetIndex[stream]=stopIndex]; IF placement.xLeft=-1 AND placement.yBottom=-1 AND placement.xWidth=-1 AND placement.yHeight=-1 THEN NULL ELSE Assert[placement.xWidth>0 AND placement.yHeight>0]; Assert[data.placement=NIL]; data.placement _ NEW[PlacementPart _ placement]; }; photometry => { photometry: PhotometryPart; TRUSTED { ReadBytes[stream, @photometry, byteSizePhotometryPart] }; Assert[IO.GetIndex[stream]<=stopIndex]; IO.SetIndex[stream, stopIndex]; -- Ignore histogram, if any Assert[data.photometry=NIL]; data.photometry _ NEW[PhotometryPart _ photometry]; }; comment => { comment: CommentPart; byteSizeComment: INT ~ stopIndex-IO.GetIndex[stream]; length: NAT _ 0; -- number of characters in the string rope: ROPE _ NIL; Assert[byteSizeComment IN[1..byteSizeCommentPart]]; TRUSTED { ReadBytes[stream, @comment, byteSizeComment] }; length _ ORD[comment[0]]; Assert[byteSizeComment>=length+1]; { -- turn the comment into a ROPE i: NAT _ 0; p: PROC RETURNS [CHAR] ~ { RETURN[comment[i _ i+1]] }; rope _ Rope.FromProc[len: length, p: p]; }; data.comments _ CONS[rope, data.comments]; }; ENDCASE => IO.SetIndex[stream, stopIndex]; -- ignore unknown part type IF IO.GetIndex[stream]=stopIndex THEN NULL ELSE ERROR IIPixelArray.Error[[code: $bug, explanation: "Bug in FromAIS."]]; ENDLOOP; IF data.raster#NIL AND data.uca#NIL THEN { samplesPerPixel: NAT ~ data.raster.samplesPerPixel; sSize: CARDINAL ~ data.raster.scanCount; fSize: CARDINAL ~ data.raster.scanLength; linesPerBlock: CARDINAL _ data.uca.scanLinesPerBlock; bytesPadding: INT _ 0; scanMode: IITransformation.ScanMode; data.bytesPerLine _ BytesForAISWords[data.uca.wordsPerScanLine]; IF linesPerBlock=nil THEN linesPerBlock _ MIN[defaultLinesPerBlock, sSize] ELSE bytesPadding _ BytesForAISWords[data.uca.paddingPerBlock]; data.bytesPerBlock _ data.bytesPerLine*linesPerBlock+bytesPadding; data.bufferMap _ IISample.NewSampleMap[ box: [min: [0,0], max: [s: linesPerBlock, f: Basics.LongMult[samplesPerPixel, fSize]]], bitsPerSample: data.uca.bitsPerSample, bitsPerLine: Basics.bitsPerByte*data.bytesPerLine ]; SELECT data.raster.scanDirection FROM 0, 8 => scanMode _ [slow: right, fast: up]; 3 => scanMode _ [slow: down, fast: right]; ENDCASE => ERROR IIPixelArray.Error[[$unimplementedAISFile, "AIS file has unimplemented scanDirection"]]; RETURN[IIPixelArrayPrivate.New[class: classAIS, data: data, immutable: TRUE, samplesPerPixel: samplesPerPixel, sSize: sSize, fSize: fSize, m: IITransformation.SFToXY[scanMode: scanMode, sSize: sSize, fSize: fSize] ]]; } ELSE { ProduceError["AIS file has no raster part."]; RETURN[NIL] }; }; classAIS: IIPixelArrayPrivate.PixelArrayClass ~ IIPixelArrayPrivate.NewClass[ type: $AIS, MaxSampleValue: MaxSampleValueAIS, GetSamples: GetSamplesAIS ]; MaxSampleValueAIS: IIPixelArrayPrivate.MaxSampleValueProc ~ { data: Data ~ NARROW[self.data]; RETURN[Basics.BITSHIFT[1, data.uca.bitsPerSample]-1]; }; GetSamplesAIS: IIPixelArrayPrivate.GetSamplesProc ~ { data: Data ~ NARROW[self.data]; entryGetSamplesAIS: ENTRY PROC [data: Data] ~ { ENABLE UNWIND => NULL; s0: CARDINAL ~ s; f0: CARDINAL ~ f; samplesPerPixel: CARDINAL ~ data.raster.samplesPerPixel; bufferMap: IISample.SampleMap ~ data.bufferMap; bufferSize: SF.Vec ~ IISample.GetSize[bufferMap]; IF s0 NOT IN[data.smin..data.smax) THEN { linesPerBlock: NAT ~ bufferSize.s; block: NAT ~ s0/linesPerBlock; -- block number containing s0 byteIndex: INT ~ data.rasterSectionIndex+block*data.bytesPerBlock; byteCount: INT _ 0; data.smin _ block*linesPerBlock; -- first scan line in block data.smax _ MIN[data.smin+linesPerBlock, data.raster.scanCount]; byteCount _ (data.smax-data.smin)*data.bytesPerLine; IO.SetIndex[self: data.stream, index: byteIndex]; TRUSTED { ReadBytes[stream: data.stream, base: IISample.GetBase[bufferMap].word, bytes: byteCount] }; }; IISample.GetSamples[map: bufferMap, initIndex: [s: s0-data.smin, f: f0*samplesPerPixel+i], delta: [s: 0, f: samplesPerPixel], buffer: buffer, start: start, count: count ]; }; entryGetSamplesAIS[data]; }; Join3AIS: PUBLIC PROC [name1, name2, name3: ROPE] RETURNS [PixelArray] ~ { RETURN[IIPixelArray.Join3[FromAIS[name1], FromAIS[name2], FromAIS[name3]]]; }; END. ZIIPixelArrayAISImpl.mesa Copyright c 1984, 1985, 1986 by Xerox Corporation. All rights reserved. Michael Plass, September 15, 1986 4:32:28 pm PDT Doug Wyatt, March 7, 1986 4:21:51 pm PST -- PROC [self: PixelArray, i: NAT] RETURNS [Sample] -- -- PROC [self: PixelArray, i: NAT, s, f: INT, buffer: SampleBuffer, start: NAT, count: NAT] -- ΚB˜codešœ™Kšœ Οmœ=™HK™0K™(—K˜šΟk ˜ Kšœžœ°˜ΓKšœžœžœ˜/Kšžœžœ˜Kšœ žœ˜.Kšœžœ˜-KšœžœF˜_Kšœ žœ9˜GKšœžœ$˜:Kšžœžœ#žœ˜CKšœžœ žœ˜Kšœžœ˜—K˜Kš Πblœžœžœžœžœ ˜>Kšžœ žœAžœ˜[Kšžœ ˜Kšœž˜K˜Kšžœžœžœ˜Kšžœžœžœžœ˜K˜Kšœ žœ˜+K˜Kšœžœ˜)Kšœ žœ"˜/K™Kšœžœ˜K˜šΟn œžœžœ˜*KšžœG˜LK˜K˜—š œžœ žœ˜"Kšžœžœ žœ5˜JKšœ˜K˜—š  œžœ žœžœžœžœ˜DKšžœ;˜AK˜K˜—š  œžœžœ žœžœžœ žœž œ˜UKšœ žœžœžœ˜SKš žœžœžœžœΟc˜IK˜K˜—K˜š  œžœžœžœžœžœ˜NKšœžœžœ˜%Kšœ žœ˜-Kšœ˜Kšœ%žœ‘˜BKšžœ9˜@Kšžœžœ.˜SKšœžœžœ˜BKšœ:˜:š žœ žœžœžœž˜$K˜Kšœ žœžœ˜&Kšœ žœ˜Kšžœ8˜?Kšœ;˜;Kšœ+˜+šžœž˜Kšœ&žœ‘˜Fšœ ˜ Kšœ˜Kšœ‘˜/Kšžœ4˜;Kšœžœ˜'Kšœžœžœ˜PKšœžœ˜'šžœž˜˜Kšœ˜Kšœžœ žœ˜4Kšœ*˜*Kšžœ-˜4Kšžœžœ‘ ˜˜>KšœJ˜JKšœ˜—K˜—Kšžœ1žœžœ˜CK˜K˜—šœM˜MKšœ ˜ Kšœ"˜"Kšœ˜Kšœ˜K˜—š œ,˜=Kšœžœžœžœ ‘™6Kšœ žœ ˜Kšžœžœ˜5K˜K˜—š  œ(˜5Kš œžœžœžœžœ žœ™^Kšœ žœ ˜šœžœžœ˜/Kšžœžœžœ˜Kšœžœ žœ˜#Kšœžœ˜8K˜/Kšœ žœ#˜1šžœžœžœžœ˜)Kšœžœ˜"Kšœžœ‘˜