IF file #
FS.nullOpenFile
THEN {
ENABLE {
UNWIND => {NULL};
ANY => {GO TO badFile}};
BcdBase:
PROC [p:
LONG
POINTER]
RETURNS [BcdDefs.Base] =
INLINE {
RETURN [LOOPHOLE[p, BcdDefs.Base]]};
bcd: BcdDefs.BcdBase;
bcdPages: CARDINAL ← 1;
mtb, ftb, sgb: BcdDefs.Base;
mti: BcdDefs.MTIndex;
sSeg: BcdDefs.SGIndex;
nString: BcdDefs.NameString;
typeId: ConvertUnsafe.SubString;
d: ConvertUnsafe.SubString;
DO
headerInterval ← VM.Allocate[count: bcdPages];
bcd ← VM.AddressForPageNumber[headerInterval.page];
FS.Read[file: file, from: 0, nPages: bcdPages, to: bcd];
IF bcd.versionIdent # BcdDefs.VersionID THEN GOTO badFile;
IF bcdPages >= bcd.nPages THEN EXIT;
bcdPages ← bcd.nPages;
VM.Free[headerInterval]; headerInterval ← VM.nullInterval
ENDLOOP;
IF bcd.nConfigs # 0 THEN GOTO badFile; -- no packaged bcd's (for now)
nString ← LOOPHOLE[bcd + bcd.ssOffset];
typeId.base ← LOOPHOLE[Rope.Flatten[formalId]];
typeId.offset ← 0;
typeId.length ← formalId.Length[];
d.base ← @nString.string;
ftb ← BcdBase[bcd + bcd.ftOffset];
mtb ← BcdBase[bcd + bcd.mtOffset]; mti ← BcdDefs.MTIndex.FIRST;
UNTIL mti = bcd.mtLimit
DO
d.offset ← mtb[mti].name; d.length ← nString.size[mtb[mti].name];
IF ConvertUnsafe.EqualSubStrings[typeId, d] THEN EXIT;
mti ← mti + (
WITH m: mtb[mti]
SELECT
FROM
direct => BcdDefs.MTRecord.direct.SIZE + m.length*BcdDefs.Link.SIZE,
indirect => BcdDefs.MTRecord.indirect.SIZE,
multiple => BcdDefs.MTRecord.multiple.SIZE,
ENDCASE => ERROR);
REPEAT
FINISHED =>
IF bcd.nModules = 1 THEN mti ← BcdDefs.MTIndex.FIRST ELSE GOTO badFile;
ENDLOOP;
ftb ← BcdBase[bcd + bcd.ftOffset];
version ←
IF mtb[mti].file = BcdDefs.FTSelf
THEN bcd.version
ELSE ftb[mtb[mti].file].version;
sgb ← BcdBase[bcd + bcd.sgOffset]; sSeg ← mtb[mti].sseg;
IF sSeg = BcdDefs.SGNull
OR sgb[sSeg].pages = 0 OR sgb[sSeg].file # BcdDefs.FTSelf THEN GO TO badFile;
span ← [base: sgb[sSeg].base - 1, pages: sgb[sSeg].pages];
DeleteHeader[];
EXITS
badFile => {DeleteHeader[]; span ← nullSpan}};