<> <> <> <> <> <> <> <<>> DIRECTORY FS USING [Error, GetInfo, nullOpenFile, Open, OpenFile, Read], Rope USING [Concat, Fetch, FromRefText, ROPE], Tfm USING [Byte, CharIc, Depth, Directory, Exten, FInfo, FInfoEntry, Fixed, FixedArray, Header, Height, Kern, LigKern, Long, Param, ParamIndex, ValidDirectory, Width, Word], TSFontTable USING [Byte, FInfoEntry, FInfoTable, FInfoTableRec, HeaderInfo, HeaderInfoRec, LigKernProgram, LigKernProgramRec, MetricTable, MetricTableRec, ParamTable, ParamTableRec, Record, Ref], TSTypes USING [pt, RealDimn], VM USING [AddressForPageNumber, Allocate, Free, Interval, nullInterval]; TSFontTableImpl: CEDAR PROGRAM IMPORTS FS, Rope, Tfm, TSTypes, VM EXPORTS TSFontTable = BEGIN OPEN TSTypes, TSFontTable; BadTfmFile: SIGNAL = CODE; TwoToTheTenth: INT = 2*2*2*2*2 * 2*2*2*2*2; TwoToTheTwentieth: INT = TwoToTheTenth*TwoToTheTenth; RealTwoToTheTwentieth: REAL = TwoToTheTwentieth; FixedToReal: PROCEDURE [x: Tfm.Fixed] RETURNS [REAL] = TRUSTED BEGIN RETURN[Tfm.Long[x]/RealTwoToTheTwentieth]; END; tfmDir: Rope.ROPE _ "[]<>Fonts>FontMetrics>"; Load: PUBLIC PROCEDURE [name: Rope.ROPE] RETURNS [f: Ref] = TRUSTED BEGIN ENABLE FS.Error => TRUSTED {GOTO FileNotFound}; s: NAT = SIZE[Tfm.Word]; tfmName: Rope.ROPE _ name.Concat[".tfm"]; tfmFile: FS.OpenFile _ FS.nullOpenFile; pages: INT; space: VM.Interval _ VM.nullInterval; base: LONG POINTER TO UNSPECIFIED; dir: LONG POINTER TO Tfm.Directory; SELECT Rope.Fetch[tfmName] FROM '/, '[ => tfmFile _ FS.Open[tfmName]; ENDCASE => { longName: Rope.ROPE _ Rope.Concat[tfmDir, tfmName]; tfmFile _ FS.Open[longName ! FS.Error => IF error.code # $unknownFile THEN CONTINUE]; IF tfmFile = FS.nullOpenFile THEN { longName _ Rope.Concat[tfmDir, tfmName]; tfmFile _ FS.Open[longName]; }; tfmName _ longName; }; pages _ FS.GetInfo[tfmFile].pages; space _ VM.Allocate[pages]; base _ VM.AddressForPageNumber[space.page]; FS.Read[file: tfmFile, from: 0, nPages: pages, to: base]; dir _ LOOPHOLE[base]; f _ NEW[TSFontTable.Record]; IF Tfm.ValidDirectory[dir^] THEN BEGIN OPEN dir^; hdr: LONG POINTER TO Tfm.Header _ LOOPHOLE[dir + s*6]; pf: LONG POINTER TO Tfm.FInfo _ LOOPHOLE[hdr + s*lh]; pw: LONG POINTER TO Tfm.Width _ LOOPHOLE[pf + s*(ec-bc+1)]; ph: LONG POINTER TO Tfm.Height _ LOOPHOLE[pw + s*nw]; pd: LONG POINTER TO Tfm.Depth _ LOOPHOLE[ph + s*nh]; pi: LONG POINTER TO Tfm.CharIc _ LOOPHOLE[pd + s*nd]; pl: LONG POINTER TO Tfm.LigKern _ LOOPHOLE[pi + s*ni]; pk: LONG POINTER TO Tfm.Kern _ LOOPHOLE[pl + s*nl]; pe: LONG POINTER TO Tfm.Exten _ LOOPHOLE[pk + s*nk]; pp: LONG POINTER TO Tfm.Param _ LOOPHOLE[pe + s*ne]; f.name _ name; f.headerInfo _ ExtractHeaderInfo[hdr]; f.bc _ VAL[bc]; f.ec _ VAL[ec]; f.fInfoTable _ ExtractFInfoTable[pf,dir]; f.widthTable _ ExtractDimensions[pw,nw]; f.heightTable _ ExtractDimensions[ph,nh]; f.depthTable _ ExtractDimensions[pd,nd]; f.charIcTable _ ExtractDimensions[pi,ni]; f.ligKernProgram _ ExtractLigKernProgram[pl,nl]; f.kernTable _ ExtractDimensions[pk,nk]; f.extTable _ NIL; -- don't need this for Tioga at this time f.parameters _ ExtractParameters[pp,np]; END ELSE {SIGNAL BadTfmFile}; VM.Free[space]; EXITS FileNotFound => {} END; ExtractHeaderInfo: UNSAFE PROCEDURE [p: LONG POINTER TO Tfm.Header] RETURNS [h: HeaderInfo] = UNCHECKED BEGIN -- h _ NEW[HeaderInfoRec]; BEGIN OPEN h^; checkSum _ p.checkSum; characterCodingScheme _ Rope.FromRefText[Textify[LOOPHOLE[@p^.characterCodingScheme]]]; family _ Rope.FromRefText[Textify[LOOPHOLE[@p^.externalFontIdentifier]]]; designSize _ RealDimn[FixedToReal[p.designSize],pt]; face _ p.extraInfo.parcFaceByte; END END; Textify: UNSAFE PROCEDURE [a: LONG POINTER TO READONLY PACKED ARRAY [0..255] OF CHARACTER] RETURNS [t: REF TEXT] = UNCHECKED BEGIN len:NAT _ LOOPHOLE[a[0],Byte]; -- length is stashed in first byte t _ NEW[TEXT[len]]; t.length _ len; FOR i:NAT IN [0..len) DO t[i] _ a[i+1]; ENDLOOP; END; nullFInfoEntry: FInfoEntry ~ [ widthIndex: 0, heightIndex: 0, depthIndex: 0, charIcIndex: 0, remainder: none[unused: 0] ]; ExtractFInfoTable: UNSAFE PROCEDURE [p: LONG POINTER TO Tfm.FInfo, dir: LONG POINTER TO Tfm.Directory] RETURNS [FInfoTable] = UNCHECKED BEGIN OPEN dir^; f: FInfoTable _ NEW[FInfoTableRec[ec+1]]; FOR i:NAT IN [0..bc) DO f[i] _ nullFInfoEntry ENDLOOP; FOR i:NAT IN [bc..ec] DO OPEN p[i-bc]; IF widthIndex >= nw OR heightIndex >= nh OR depthIndex >= nd OR charIcIndex >= ni THEN SIGNAL BadTfmFile; f[i] _ p[i-bc] ENDLOOP; RETURN[f] END; ExtractDimensions: UNSAFE PROCEDURE [p: LONG POINTER TO Tfm.FixedArray, n:CARDINAL] RETURNS [d: MetricTable] = UNCHECKED BEGIN d _ NEW[MetricTableRec[n]]; FOR i:NAT IN [0..n) DO d[i] _ FixedToReal[p[i]] ENDLOOP END; ExtractLigKernProgram: UNSAFE PROCEDURE [p: LONG POINTER TO Tfm.LigKern, n:CARDINAL] RETURNS [l: LigKernProgram] = UNCHECKED BEGIN l _ NEW[LigKernProgramRec[n]]; FOR i:NAT IN [0..n) DO l[i] _ p[i] ENDLOOP END; ExtractParameters: UNSAFE PROCEDURE [p: LONG POINTER TO Tfm.Param, n:CARDINAL] RETURNS [t: ParamTable] = UNCHECKED BEGIN i: Tfm.ParamIndex _ FIRST[Tfm.ParamIndex]; t _ NEW[ParamTableRec[n]]; THROUGH [0..n) DO t[i] _ FixedToReal[p[i]]; i _ SUCC[i]; ENDLOOP; t.slantNum _ Tfm.Long[p[slant].ValueTimesTwoToTheTwentieth]; t.slantDenom _ TwoToTheTwentieth; END; END. <> <> <> <> <>