DIRECTORY AISFileFormat USING [AttributeHeader, byteSizeAttributeHeader, byteSizeCommentPart, byteSizePartHeader, byteSizePhotometryPart, byteSizePlacementPart, byteSizeRasterPart, byteSizeUCACoding, bytesPerAISWord, CommentPart, nil, PartHeader, passwordValue, PhotometryPart, PlacementPart, RasterPart, UCACoding, wordsPerAISPage], Basics USING [HWORD, BITSHIFT, bitsPerByte, Int16FromH, Card16FromH], ImagerError USING [Error], ImagerPixelArray USING [Join3, PixelArray], ImagerPixelArrayAIS USING [], ImagerPixelArrayAISPrivate USING [Data, DataRep], ImagerPixelArrayPrivate USING [GetSamplesProc, MaxSampleValueProc, New, NewClass, PixelArrayClass], ImagerSample USING [GetBase, GetSamples, GetSize, NewSampleMap, RasterSampleMap], ImagerSys USING [OpenInputFile], ImagerTransformation USING [ScanMode, SFToXY, Transformation], IO USING [EndOfStream, GetIndex, SetIndex, STREAM, UnsafeGetBlock], Rope USING [Concat, FromProc, ROPE], SF USING [Vec]; ImagerPixelArrayAISImpl: CEDAR MONITOR LOCKS data USING data: Data IMPORTS Basics, ImagerError, ImagerPixelArray, ImagerPixelArrayPrivate, ImagerSample, ImagerSys, ImagerTransformation, IO, Rope EXPORTS ImagerPixelArrayAIS ~ BEGIN ROPE: TYPE ~ Rope.ROPE; STREAM: TYPE ~ IO.STREAM; Int16: TYPE ~ Basics.HWORD; Card16: TYPE ~ Basics.HWORD; IOrd: PROC [h: Int16] RETURNS [INT16] ~ INLINE { RETURN [Basics.Int16FromH[h]] }; COrd: PROC [h: Card16] RETURNS [CARD16] ~ INLINE { RETURN [Basics.Card16FromH[h]] }; PixelArray: TYPE ~ ImagerPixelArray.PixelArray; Data: TYPE ~ ImagerPixelArrayAISPrivate.Data; DataRep: TYPE ~ ImagerPixelArrayAISPrivate.DataRep; defaultLinesPerBlock: NAT ¬ 16; ProduceError: PROC [explanation: ROPE] ~ { ERROR ImagerError.Error[[code: $syntax, explanation: explanation]]; }; Assert: PROC [assertion: BOOL] ~ { IF NOT assertion THEN ProduceError["AIS file structure is inconsistent."]; }; BytesForAISWords: PROC [aisWords: INT] RETURNS [INT] ~ INLINE { RETURN[LONG[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 ~ ImagerSys.OpenInputFile[name]; data: Data ~ NEW[DataRep ¬ [stream: stream]]; header: MACHINE DEPENDENT RECORD [ c: AttributeHeader, p: PACKED ARRAY [0..(BITS[WORD]-(BITS[AttributeHeader] MOD BITS[WORD])) MOD BITS[WORD]) OF [0..1] ]; m: ImagerTransformation.Transformation ¬ NIL; -- from [s, f] to [x, y] IF stream = NIL THEN ERROR ImagerError.Error[[code: $fileNotFound, explanation: Rope.Concat["File not found: ", name]]]; TRUSTED { ReadBytes[stream, @header, byteSizeAttributeHeader] }; IF header.c.password#passwordValue THEN ProduceError["AIS password value is wrong."]; Assert[COrd[header.c.length]>0 AND (COrd[header.c.length] MOD wordsPerAISPage)=0]; data.rasterSectionIndex ¬ BytesForAISWords[COrd[header.c.length]]; FOR firstPart: BOOL ¬ TRUE, FALSE DO partHeader: MACHINE DEPENDENT RECORD [ c: PartHeader, p: PACKED ARRAY [0..(BITS[WORD]-(BITS[PartHeader] MOD BITS[WORD])) MOD BITS[WORD]) OF [0..1] ]; startIndex: INT ~ IO.GetIndex[stream]; stopIndex: INT; TRUSTED { ReadBytes[stream, @partHeader, byteSizePartHeader] }; stopIndex ¬ startIndex+BytesForAISWords[256*partHeader.c.lengthHi+partHeader.c.lengthLo]; Assert[stopIndex<=data.rasterSectionIndex]; SELECT partHeader.c.type FROM nil => { Assert[partHeader.c.lengthHi=0 AND partHeader.c.lengthLo=0]; EXIT }; -- should be a zero word raster => { raster: MACHINE DEPENDENT RECORD [ c: RasterPart, p: PACKED ARRAY [0..(BITS[WORD]-(BITS[RasterPart] MOD BITS[WORD])) MOD BITS[WORD]) OF [0..1] ]; Assert[firstPart]; -- raster part must be first TRUSTED { ReadBytes[stream, @raster, byteSizeRasterPart] }; Assert[IO.GetIndex[stream]<=stopIndex]; Assert[COrd[raster.c.scanCount]>0 AND COrd[raster.c.scanLength]>0 AND COrd[raster.c.samplesPerPixel]>0]; data.raster ¬ NEW[RasterPart ¬ raster.c]; SELECT raster.c.codingType FROM uca => { uca: MACHINE DEPENDENT RECORD [ c: UCACoding, p: PACKED ARRAY [0..(BITS[WORD]-(BITS[UCACoding] MOD BITS[WORD])) MOD BITS[WORD]) OF [0..1] ]; byteSizeCoding: INT ~ stopIndex-IO.GetIndex[stream]; Assert[byteSizeCoding<=byteSizeUCACoding]; TRUSTED { ReadBytes[stream, @uca, byteSizeCoding] }; IF COrd[uca.c.bitsPerSample]=0 THEN uca.c.bitsPerSample.lo ¬ 1; -- kludge Assert[INT[COrd[uca.c.bitsPerSample]]*INT[COrd[raster.c.samplesPerPixel]]*INT[COrd[raster.c.scanLength]] <=INT[Basics.bitsPerByte]*BytesForAISWords[COrd[uca.c.wordsPerScanLine]]]; IF byteSizeCoding ProduceError["Unknown AIS coding type."]; }; placement => { placement: MACHINE DEPENDENT RECORD [ c: PlacementPart, p: PACKED ARRAY [0..(BITS[WORD]-(BITS[PlacementPart] MOD BITS[WORD])) MOD BITS[WORD]) OF [0..1] ]; TRUSTED { ReadBytes[stream, @placement, byteSizePlacementPart] }; Assert[IO.GetIndex[stream]=stopIndex]; IF IOrd[placement.c.xLeft]=-1 AND IOrd[placement.c.yBottom]=-1 AND IOrd[placement.c.xWidth]=-1 AND IOrd[placement.c.yHeight]=-1 THEN NULL ELSE Assert[IOrd[placement.c.xWidth]>0 AND IOrd[placement.c.yHeight]>0]; Assert[data.placement=NIL]; data.placement ¬ NEW[PlacementPart ¬ placement.c]; }; photometry => { photometry: MACHINE DEPENDENT RECORD [ c: PhotometryPart, p: PACKED ARRAY [0..(BITS[WORD]-(BITS[PhotometryPart] MOD BITS[WORD])) MOD BITS[WORD]) OF [0..1] ]; 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.c]; }; comment => { comment: MACHINE DEPENDENT RECORD [ c: CommentPart, p: PACKED ARRAY [0..(BITS[WORD]-(BITS[CommentPart] MOD BITS[WORD])) MOD BITS[WORD]) OF [0..1] ]; 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.c[0]]; Assert[byteSizeComment>=INT[length+1]]; { -- turn the comment into a ROPE i: NAT ¬ 0; p: PROC RETURNS [CHAR] ~ { RETURN[comment.c[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 ImagerError.Error[[code: $bug, explanation: "Bug in FromAIS."]]; ENDLOOP; IF data.raster#NIL AND data.uca#NIL THEN { samplesPerPixel: NAT ~ COrd[data.raster.samplesPerPixel]; sSize: CARDINAL ~ COrd[data.raster.scanCount]; fSize: CARDINAL ~ COrd[data.raster.scanLength]; linesPerBlock: CARDINAL ¬ COrd[data.uca.scanLinesPerBlock]; bytesPadding: INT ¬ 0; scanMode: ImagerTransformation.ScanMode; data.bytesPerLine ¬ BytesForAISWords[COrd[data.uca.wordsPerScanLine]]; IF data.uca.scanLinesPerBlock=nil THEN linesPerBlock ¬ MIN[defaultLinesPerBlock, sSize] ELSE bytesPadding ¬ BytesForAISWords[COrd[data.uca.paddingPerBlock]]; data.bytesPerBlock ¬ data.bytesPerLine*linesPerBlock+bytesPadding; data.bufferMap ¬ ImagerSample.NewSampleMap[ box: [min: [0, 0], max: [s: linesPerBlock, f: samplesPerPixel*fSize]], bitsPerSample: COrd[data.uca.bitsPerSample], bitsPerLine: Basics.bitsPerByte*data.bytesPerLine ]; SELECT COrd[data.raster.scanDirection] FROM 0, 8 => scanMode ¬ [slow: right, fast: up]; 3 => scanMode ¬ [slow: down, fast: right]; ENDCASE => ERROR ImagerError.Error[[$unimplemented, "AIS file has unimplemented scanDirection"]]; RETURN[ImagerPixelArrayPrivate.New[class: classAIS, data: data, immutable: TRUE, samplesPerPixel: samplesPerPixel, sSize: sSize, fSize: fSize, m: ImagerTransformation.SFToXY[scanMode: scanMode, sSize: sSize, fSize: fSize] ]]; } ELSE { ProduceError["AIS file has no raster part."]; RETURN[NIL] }; }; classAIS: ImagerPixelArrayPrivate.PixelArrayClass ~ ImagerPixelArrayPrivate.NewClass[ type: $AIS, MaxSampleValue: MaxSampleValueAIS, GetSamples: GetSamplesAIS ]; MaxSampleValueAIS: ImagerPixelArrayPrivate.MaxSampleValueProc ~ { data: Data ~ NARROW[pa.data]; RETURN[Basics.BITSHIFT[1, COrd[data.uca.bitsPerSample]]-1]; }; GetSamplesAIS: ImagerPixelArrayPrivate.GetSamplesProc ~ { data: Data ~ NARROW[pa.data]; entryGetSamplesAIS: ENTRY PROC [data: Data] ~ { ENABLE UNWIND => NULL; s0: CARDINAL ~ s; f0: CARDINAL ~ f; samplesPerPixel: CARDINAL ~ COrd[data.raster.samplesPerPixel]; bufferMap: ImagerSample.RasterSampleMap ~ data.bufferMap; bufferSize: SF.Vec ~ ImagerSample.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, COrd[data.raster.scanCount]]; byteCount ¬ (data.smax-data.smin)*data.bytesPerLine; IO.SetIndex[data.stream, byteIndex]; TRUSTED { ReadBytes[stream: data.stream, base: ImagerSample.GetBase[bufferMap].word, bytes: byteCount] }; }; ImagerSample.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[ImagerPixelArray.Join3[FromAIS[name1], FromAIS[name2], FromAIS[name3]]]; }; END. κ ImagerPixelArrayAISImpl.mesa Copyright Σ 1984, 1985, 1986, 1987, 1992 by Xerox Corporation. All rights reserved. Michael Plass, February 3, 1992 12:04 pm PST Doug Wyatt, March 7, 1986 4:21:51 pm PST foo: MACHINE DEPENDENT RECORD [ c: Foo, p: PACKED ARRAY [0..(BITS[WORD]-(BITS[Foo] MOD BITS[WORD])) MOD BITS[WORD]) OF [0..1] ]; -- PROC [pa: PixelArray, i: NAT] RETURNS [Sample] -- -- PROC [pa: PixelArray, i: NAT, s, f: INT, buffer: SampleBuffer, start: NAT, count: NAT] -- Κ –(cedarcode) style•NewlineDelimiter ™codešœ™Kšœ ΟeœI™TK™,K™(—K˜šΟk ˜ Kšœžœ°˜ΓKšœžœžœžœ(˜EKšœ žœ ˜Kšœžœ˜+Kšœžœ˜Kšœžœ˜1KšœžœF˜cKšœ žœ?˜QKšœ žœ˜ Kšœžœ$˜>Kšžœžœ#žœ˜CKšœžœžœ˜$Kšžœžœ˜—K˜Kš Πblœžœžœžœžœ ˜BKšžœpžœ˜Kšžœ˜Kšœž˜K˜Kšžœžœžœ˜Kšžœžœžœžœ˜Kšœžœ žœ˜šœžœ žœ˜K˜—Kš Οnœžœ žœžœžœžœ˜QKš  œžœ žœžœžœžœ˜TK˜Kšœ žœ˜/K˜Kšœžœ#˜-Kšœ žœ&˜3K™Kšœžœ˜K˜š  œžœžœ˜*Kšžœ>˜CK˜K˜—š œžœ žœ˜"Kšžœžœ žœ5˜JKšœ˜K˜—š  œžœ žœžœžœžœ˜?Kšžœžœ*˜5K˜K˜—š  œžœžœ žœžœžœ žœž œ˜UKšœ žœžœžœ˜SKš žœžœžœžœΟc˜IK˜K˜—K˜š  œžœžœžœžœžœ˜NKšœžœ!˜/Kšœ žœ˜-š Οtœ’œžœž œžœ™!Kšœ’œ’œ™ Kšœžœžœžœžœžœ’œ’œžœžœžœžœžœžœžœ™WKšœ™—šœžœž œžœ˜"Kšœ˜Kšœžœžœžœžœžœžœžœžœžœžœžœžœ˜aKšœ˜—Kšœ)žœ‘˜FKšžœ žœžœžœ^˜xKšžœ9˜@Kšžœ!žœ.˜UKšœžœžœ˜RK˜Bš žœ žœžœžœž˜$šœ žœž œžœ˜&Kšœ˜Kšœžœžœžœžœžœ žœžœžœžœžœžœžœ˜\Kšœ˜—Kšœ žœžœ˜&Kšœ žœ˜Kšžœ8˜?K˜YKšœ+˜+šžœž˜Kšœ(žœžœ‘˜fšœ ˜ šœžœž œžœ˜"Kšœ˜Kšœžœžœžœžœžœ žœžœžœžœžœžœžœ˜\Kšœ˜—Kšœ‘˜/Kšžœ4˜;Kšœžœ˜'Kšœ"žœžœ#˜hKšœžœ˜)šžœž˜˜šœžœž œžœ˜Kšœ ˜ Kšœžœžœžœžœžœ žœžœžœžœžœžœžœ˜[Kšœ˜—Kšœžœ žœ˜4Kšœ*˜*Kšžœ-˜4Kšžœžœ‘ ˜IKš œžœžœ!žœžœE˜³šžœ"žœ˜*Kšœ$˜$K˜K˜—Kšœ žœ˜"K˜—Kšžœ-˜4—K˜—šœ˜šœ žœž œžœ˜%Kšœ˜Kšœžœžœžœžœžœžœžœžœžœžœžœžœ˜_Kšœ˜—Kšžœ:˜AKšœžœ˜&Kšžœžœ˜>Kšžœžœžœž˜JKšžœ#žœ˜HKšœžœ˜Kšœžœ˜2K˜—šœ˜šœ žœž œžœ˜&Kšœ˜Kšœžœžœžœžœžœžœžœžœžœžœžœžœ˜`Kšœ˜—Kšžœ<˜CKšœžœ˜'Kšžœ‘˜;Kšœžœ˜Kšœžœ ˜5K˜—šœ ˜ šœ žœž œžœ˜#Kšœ˜Kšœžœžœžœžœžœžœžœžœžœžœžœžœ˜]Kšœ˜—Kšœžœ žœ˜5Kšœžœ‘%˜6Kšœžœžœ˜Kšœžœ˜3Kšžœ2˜9Kšœ žœ˜Kšœžœ ˜'šœ‘˜!Kšœžœ˜ Kš œžœžœžœžœ˜8K˜(Kšœ˜—Kšœžœ˜*K˜—Kšžœžœ‘˜F—Kšžœžœžœž˜*KšžœžœA˜KKšžœ˜—š žœ žœžœ žœžœ˜*Kšœžœ%˜9Kšœžœ˜.Kšœžœ ˜/Kšœžœ$˜;Kšœžœ˜Kšœ(˜(K˜Fšžœ˜!Kšžœžœ˜5KšžœA˜E—K˜B˜+KšœG˜GKšœ-˜-Kšœ1˜1Kšœ˜—šžœ!ž˜+K˜+K˜*KšžœžœR˜b—šžœEžœ˜PKšœ>˜>KšœN˜NKšœ˜—K˜—Kšžœ1žœžœ˜CK˜K˜—šœU˜UKšœ ˜ Kšœ"˜"Kšœ˜Kšœ˜K˜—š œ0˜AKšœžœžœžœ ‘™4Kšœ žœ ˜Kšžœžœ%˜;K˜K˜—š  œ,˜9Kš œžœžœžœžœ žœ™\Kšœ žœ ˜šœžœžœ˜/Kšžœžœžœ˜Kšœžœ žœ˜#Kšœžœ%˜>K˜9Kšœ žœ'˜5šžœžœžœžœ˜*Kšœžœ˜"Kšœžœ‘˜