ELSE {
-- rolling our own
Int16: TYPE ~ Basics.HWORD;
Card16: TYPE ~ Basics.HWORD;
AttributeHeader: TYPE ~ AISFileFormat.AttributeHeader;
PartHeader: TYPE ~ AISFileFormat.PartHeader;
RasterPart: TYPE ~ AISFileFormat.RasterPart;
UCACoding: TYPE ~ AISFileFormat.UCACoding;
PlacementPart: TYPE ~ AISFileFormat.PlacementPart;
PhotometryPart: TYPE ~ AISFileFormat.PhotometryPart;
CommentPart: TYPE ~ AISFileFormat.CommentPart;
IOrd: PROC [h: Int16] RETURNS [INT16] ~ {RETURN[Basics.Int16FromH[h]]};
COrd: PROC [h: Card16] RETURNS [CARD16] ~ {RETURN[Basics.Card16FromH[h]]};
Assert:
PROC [title:
ROPE, assertion:
BOOL] ~ {
IF assertion THEN RETURN;
PrintInfo[info];
IO.PutF1[s, "\tAIS file structure is inconsistent (%g)\n", IO.rope[title]];
IO.Close[in];
AISError[];
};
in: IO.STREAM ~ PFS.StreamOpen[PFS.PathFromRope[name], read];
header:
MACHINE
DEPENDENT
RECORD [
c: AttributeHeader, p: PACKED ARRAY [0..(BITS[WORD]-(BITS[AttributeHeader] MOD BITS[WORD])) MOD BITS[WORD]) OF [0..1]];
partHeader:
MACHINE
DEPENDENT
RECORD [
c: PartHeader, p: PACKED ARRAY [0..(BITS[WORD]-(BITS[PartHeader] MOD BITS[WORD])) MOD BITS[WORD]) OF [0..1]];
raster:
MACHINE
DEPENDENT
RECORD [
c: RasterPart, p: PACKED ARRAY [0..(BITS[WORD]-(BITS[RasterPart] MOD BITS[WORD])) MOD BITS[WORD]) OF [0..1]];
uca:
MACHINE
DEPENDENT
RECORD [
c: UCACoding, p: PACKED ARRAY [0..(BITS[WORD]-(BITS[UCACoding] MOD BITS[WORD])) MOD BITS[WORD]) OF [0..1]];
placement:
MACHINE
DEPENDENT
RECORD [
c: PlacementPart, p: PACKED ARRAY [0..(BITS[WORD]-(BITS[PlacementPart] MOD BITS[WORD])) MOD BITS[WORD]) OF [0..1]];
photometry:
MACHINE
DEPENDENT
RECORD [
c: PhotometryPart, p: PACKED ARRAY [0..(BITS[WORD]-(BITS[PhotometryPart] MOD BITS[WORD])) MOD BITS[WORD]) OF [0..1]];
comment:
MACHINE
DEPENDENT
RECORD [
c: CommentPart, p: PACKED ARRAY [0..(BITS[WORD]-(BITS[CommentPart] MOD BITS[WORD])) MOD BITS[WORD]) OF [0..1]];
info ¬ NEW[AISIO.InfoRep];
TRUSTED {ReadBytes[in, @header, AISFileFormat.byteSizeAttributeHeader]};
IF header.c.password # AISFileFormat.passwordValue THEN Assert["bad password", FALSE];
Assert["bad header size", COrd[header.c.length]>0 AND (COrd[header.c.length] MOD AISFileFormat.wordsPerAISPage)=0];
info.rasterOffset ¬ BytesForAISWords[COrd[header.c.length]];
FOR firstPart:
BOOL ¬
TRUE,
FALSE
DO
startIndex, stopIndex: INT ¬ IO.GetIndex[in];
TRUSTED {ReadBytes[in, @partHeader, AISFileFormat.byteSizePartHeader]};
stopIndex ¬ startIndex+BytesForAISWords[256*partHeader.c.lengthHi+partHeader.c.lengthLo];
Assert["header bigger than rasterOffset", stopIndex <= info.rasterOffset];
SELECT partHeader.c.type
FROM
nil => {
Assert["bad length for nil part", partHeader.c.lengthHi = 0 AND partHeader.c.lengthLo = 0];
EXIT; -- only correct way out
}; -- should be a zero word
raster => {
Assert["raster not first", firstPart]; -- raster part must be first
TRUSTED {ReadBytes[in, @raster, AISFileFormat.byteSizeRasterPart]};
Assert["part size too large", IO.GetIndex[in] <= stopIndex];
Assert["bad raster part size", COrd[raster.c.scanCount]>0 AND COrd[raster.c.scanLength]>0 AND COrd[raster.c.samplesPerPixel]>0];
SELECT raster.c.codingType
FROM
uca => {
byteSizeCoding: INT ~ stopIndex-IO.GetIndex[in];
Assert["bad byteSizeCoding", byteSizeCoding <= AISFileFormat.byteSizeUCACoding];
TRUSTED {ReadBytes[in, @uca, byteSizeCoding]};
IF COrd[uca.c.bitsPerSample] = 0 THEN uca.c.bitsPerSample.lo ¬ 1; -- kludge
Assert["bad scans part", 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 < AISFileFormat.byteSizeUCACoding
THEN {
Assert["bad scanLinesPerBlock", uca.c.scanLinesPerBlock = AISFileFormat.nil];
uca.c.paddingPerBlock ¬ AISFileFormat.nil;
};
info.uca ¬ NEW[UCACoding ¬ uca.c];
};
ENDCASE => Assert["Unknown AIS coding type", FALSE];
info.raster ¬ NEW[RasterPart ¬ raster.c];
};
placement => {
TRUSTED {ReadBytes[in, @placement, AISFileFormat.byteSizePlacementPart]};
Assert["bad placement part size", IO.GetIndex[in] = 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["bad place coordinates", IOrd[placement.c.xWidth]>0 AND IOrd[placement.c.yHeight]>0];
info.placement ¬ NEW[PlacementPart ¬ placement.c];
};
photometry => {
TRUSTED {ReadBytes[in, @photometry, AISFileFormat.byteSizePhotometryPart]};
Assert["bad photometry part size", IO.GetIndex[in] <= stopIndex];
IO.SetIndex[in, stopIndex]; -- Ignore histogram, if any
info.photometry ¬ NEW[PhotometryPart ¬ photometry.c];
};
comment => {
byteSizeComment: INT ~ stopIndex-IO.GetIndex[in];
length: NAT ¬ 0; -- number of characters in the string
Assert["bad comment part size", byteSizeComment IN [1..AISFileFormat.byteSizeCommentPart]];
TRUSTED {ReadBytes[in, @comment, byteSizeComment]};
length ¬ ORD[comment.c[0]];
Assert["bad comment part size", 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 ¬ Rope.FromProc[len: length, p: p];
info.comments ¬ CONS[rope, info.comments];
};
};
ENDCASE => Assert["unknown part", TRUE];
IF IO.GetIndex[in] # stopIndex THEN Assert["header # sum of parts", FALSE];
ENDLOOP;
IO.Close[in];
PrintInfo[info];
};