DIRECTORY Basics USING [Byte, BytePair], Cubic USING [Bezier, CoeffsToBezier, Coeffs], GFileFormatDefs, GriffinToTA, GriffinToTANodes, GriffinToTAPrivate, GriffinToJaM, Graphics USING [Path, MoveTo, LineTo, CurveTo, NewPath], CGPath USING [Empty], IO, FS USING [Error, StreamOpen], PairList, PrincOps USING [bytesPerPage], PrincOpsUtils USING [LongCOPY], RealConvert USING [Mesa5ToIeee], Rope, SplineDefs, StyleDefs, Vector USING [Vec]; GriffinToTAImpl: CEDAR PROGRAM IMPORTS Cubic, GriffinToTANodes, GriffinToTAPrivate, IO, PairList, PrincOpsUtils, RealConvert, Rope, SplineDefs, FS, Graphics, CGPath, GriffinToJaM EXPORTS GriffinToTA = { ROPE: TYPE = Rope.ROPE; GriffinFileError: PUBLIC SIGNAL[why: ROPE] = CODE; ViewType: TYPE = GriffinToTA.ViewType; FigureNumber: TYPE = CARDINAL[1 .. 100]; FontRef: TYPE = GriffinToTA.FontRef; StyleRef: TYPE = GriffinToTA.StyleRef; ObjectRef: TYPE = GriffinToTA.ObjectRef; PathRef: TYPE = GriffinToTA.PathRef; CaptionRef: TYPE = GriffinToTA.CaptionRef; CaptionRec: TYPE = GriffinToTA.CaptionRec; ColorRef: TYPE = GriffinToTA.ColorRef; PathStyleRef: TYPE = GriffinToTA.PathStyleRef; PathStyleRec: TYPE = GriffinToTA.PathStyleRec; CaptionStyleRef: TYPE = GriffinToTA.CaptionStyleRef; CaptionStyleRec: TYPE = GriffinToTA.CaptionStyleRec; IntegerVec: TYPE = RECORD[ x, y: INTEGER]; fontMap: PUBLIC PairList.Relation; -- styleMap: PUBLIC PairList.Relation; -- objectMap: PUBLIC PairList.Relation; -- pathMap: PUBLIC PairList.Relation; -- captionMap: PUBLIC PairList.Relation; -- clusterMap: PUBLIC PairList.Relation; -- objectsReversed: BOOLEAN _ FALSE; firstCluster, lastCluster: PUBLIC CARDINAL _ 0; colors: PUBLIC ColorRef _ NIL; colorNumber: PUBLIC CARDINAL _ 0; pathStyles: PUBLIC PathStyleRef _ NIL; pathStyleNumber: PUBLIC CARDINAL _ 0; captionStyles: PUBLIC CaptionStyleRef _ NIL; captionStyleNumber: PUBLIC CARDINAL _ 0; objectNumber: CARDINAL _ 1; -- count of objects in this view inThisView: BOOLEAN _ FALSE; diskHandle: IO.STREAM; maxCPairCount: CARDINAL = 2000; -- just for safety majorVersion: Basics.Byte = 1; minorVersion: Basics.Byte = 4; realConvert: BOOLEAN _ FALSE; -- convert reals if older than Griffin version 1.4 ConvertFile: PUBLIC PROCEDURE[fileName: ROPE, view: ViewType] = { IF view = both THEN view _ main; fileName _ FixFileName[fileName, ".Griffin"]; diskHandle _ FS.StreamOpen[fileName ! FS.Error => CHECKED {GOTO BadCreate}]; InitDataStructures[]; ReadFigure[1, view]; IF ~objectsReversed THEN { clusterMap _ ReverseRelation[clusterMap]; objectsReversed _ TRUE}; GriffinToTANodes.PutClusters[FixFileName[fileName, ".Artwork"]]; GriffinToTANodes.PutStyles[FixFileName[fileName, ".Style"]]; DestroyDataStructures[]; IO.Close[diskHandle]; EXITS BadCreate => {SIGNAL GriffinFileError[Rope.Cat["file ", fileName, " not found"]]}; }; ConvertFileToJaM: PUBLIC PROCEDURE[fileName: ROPE, view: ViewType] = { IF view = both THEN view _ main; fileName _ FixFileNIme[fileName, ".Griffin"]; diskHandle _ FS.StreamOpen[fileName ! FS.Error => CHECKED {GOTO BqdCreate}]; InitDataStructures[]; ReadFigure[1, view]; IF ~objectsReversed THEN { clusterMap _ ReverseRelation[clusterMap]; objectsReversed _ TRUE}; GriffinToJaM.PutClusters[FixFileName[fileName, ".JaM"]]; DestroyDataStructures[]; IO.Close[diskHandle]; EXITS BadCreate => {SIGNAL GriffinFileError[Rope.Cat["file ", fileName, " not found"]]}; }; InitDataStructures: PROCEDURE = { colors _ GriffinToTAPrivate.InitColors[]; fontMap _ PairList.CreateRelation[]; styleMap _ PairList.CreateRelation[]; objectMap _ PairList.CreateRelation[]; pathMap _ PairList.CreateRelation[]; captionMap _ PairList.CreateRelation[]; clusterMap _ PairList.CreateRelation[]; objectsReversed _ FALSE; firstCluster _ 0; lastCμuster _ 0; pathStyles _ NIL; pathStyleNumber _ 0; captionStyles _ NIL; captionStyleNumber _ 0; }; DestroyDataStructures: PROCEDURE = { PairList.DestroyRelation[fontMap]; PairList.DestroyRelation[styleMap]; PairList.DestroyRelation[objectMap]; PairList.DestroyRelation[pathMap]; PairList.DestroyRelation[captionMap]; PairList.DestroyRelation[clusterMap]; pathStyles _ NIL; captionStyles _ NIL; colors _ NIL; }; ReadFigure: PROCEDURE[fignum: FigureNumber, view: ViewType] = TRUSTED { fileheader: GFileFormatDefs.GFileHeader; hcontrol: GFileFormatDefs.GFileHardcopyController; dcontrol: GFileFormatDefs.GFileDisplayController; figurename: GFileFormatDefs.GFileFigureName; fontCount, styleCount, objectCount, f, s: CARDINAL; ReadHeader[@fileheader]; MoveToSector[fileheader.figure[fignum]]; -- position to the right sector ReadStructure[@figurename, GFileFormatDefs.lGFileFigureName]; ReadStructure[@hcontrol, GFileFormatDefs.lGFileHardcopyController]; ReadStructure[@dcontrol, GFileFormatDefs.lGFileDisplayController]; IF dcontrol.numcontrolpairs > maxCPairCount THEN SIGNAL GriffinFileError["too many control pairs"]; fontCount _ ReadWord[]; FOR f IN [1 .. fontCount] DO ReadFont[f, fontMap]; ENDLOOP; styleCount _ ReadWord[]; FOR s IN [1 .. styleCount] DO ReadStyle[s, styleMap]; ENDLOOP; objectCount _ ReadWord[]; THROUGH [1 .. objectCount] DO ReadObject[objectMap, view]; ENDLOOP; }; ReadHeader: PROCEDURE[h: LONG POINTER TO GFileFormatDefs.GFileHeader] = TRUSTED { IO.SetIndex[diskHandle,0]; ReadStructure[h, GFileFormatDefs.lGFileHeader]; realConvert _ FALSE; IF h.majversion#majorVersion OR h.minversion#minorVersion THEN { IF h.majversion=1 AND h.minversion IN [0..3] THEN realConvert _ TRUE; }; }; ReadFont: PROCEDURE[fontNumber: CARDINAL, fontMap: PairList.Relation] = { font: FontRef _ NEW[GFileFormatDefs.GFileFont]; refFontId: REF CARDINAL _ NEW[CARDINAL _ fontNumber]; ReadStructure[LOOPHOLE[font], GFileFormatDefs.lGFileFont]; PairList.AddPair[fontMap, refFontId, font]; }; ReadStyle: PROCEDURE[styleNumber: CARDINAL, styleMap: PairList.Relation] = { style: StyleRef _ NEW[GFileFormatDefs.GFileStyle]; refStyleId: REF CARDINAL _ NEW[CARDINAL _ styleNumber]; ReadStructure[LOOPHOLE[style], GFileFormatDefs.lGFileStyle]; TRUSTED { style.thickness _ GetReal[LOOPHOLE[style.thickness]] }; PairList.AddPair[styleMap, refStyleId, style]; }; ReadObject: PROCEDURE[objectMap: PairList.Relation, view: ViewType] = TRUSTED { fileObjectRef: ObjectRef _ NEW[GFileFormatDefs.GFileObject]; topScreenCoord: INTEGER = 808; origin: IntegerVec; path: PathRef _ Graphics.NewPath[]; refCaption: CaptionRef _ NIL; ReadStructure[LOOPHOLE[fileObjectRef], GFileFormatDefs.lGFileObject]; inThisView _ ((view=main) AND (~fileObjectRef^.hidewindow)) OR ((view=alternate) AND (fileObjectRef^.hidewindow)); origin.x _ fileObjectRef^.bleft; origin.y _ topScreenCoord - fileObjectRef^.bbottom; SELECT fileObjectRef^.objtype FROM GFileFormatDefs.typeCurveObject, GFileFormatDefs.typeAreaObject => { nlinks: CARDINAL _ ReadWord[]; splinetype: SplineDefs.SplineType _ SELECT fileObjectRef^.splinetype FROM GFileFormatDefs.typeNUMSpline => naturalUM, GFileFormatDefs.typeCUMSpline => cyclicUM, GFileFormatDefs.typeNALSpline => naturalAL, GFileFormatDefs.typeCALSpline => cyclicAL, GFileFormatDefs.typeBEZSpline => bezier, GFileFormatDefs.typeBSISpline => bsplineInterp, GFileFormatDefs.typeBSpline => bspline, GFileFormatDefs.typeCRSpline => crspline, ENDCASE => bspline; SELECT fileObjectRef^.trajtype FROM GFileFormatDefs.typeLinkedTraj => AppendPathLinks[nlinks, splinetype, FALSE, origin, path]; GFileFormatDefs.typeCSTraj => { IF nlinks#1 THEN SIGNAL GriffinFileError["imposible cyclic spline"]; splinetype _ (SELECT splinetype FROM naturalUM => cyclicUM, naturalAL => cyclicAL, ENDCASE => splinetype); AppendPathLinks[1, splinetype, TRUE, origin, path]; }; ENDCASE => SIGNAL GriffinFileError["invalid trajectory"]; }; GFileFormatDefs.typeCaptionObject => { fcaptiontrailer: GFileFormatDefs.GFileCaptionTrailer; captionText: ROPE; pt: Vector.Vec; ReadStructure[@fcaptiontrailer, GFileFormatDefs.lGFileCaptionTrailer]; pt.x _ GetReal[fcaptiontrailer.xanchor]; pt.y _ GetReal[fcaptiontrailer.yanchor]; pt.x _ GriffinToTAPrivate.ScalePressToScreenCoord[pt.x]; pt.y _ GriffinToTAPrivate.ScalePressToScreenCoord[pt.y]; captionText _ ReadString[]; refCaption _ NEW[CaptionRec _ [pt, captionText]]; }; ENDCASE => SIGNAL GriffinFileError["bad object"]; IF inThisView THEN { refObjectId: REF CARDINAL _ NEW[CARDINAL _ objectNumber]; refClusterId: REF CARDINAL _ NEW[CARDINAL _ fileObjectRef^.cluster]; PairList.AddPair[objectMap, refObjectId, fileObjectRef]; objectNumber _ objectNumber+1; SELECT fileObjectRef^.objtype FROM GFileFormatDefs.typeCurveObject, GFileFormatDefs.typeAreaObject => PairList.AddPair[pathMap, refObjectId, path]; GFileFormatDefs.typeCaptionObject => PairList.AddPair[captionMap, refObjectId, refCaption]; ENDCASE; firstCluster _ MIN[firstCluster, fileObjectRef^.cluster]; lastCluster _ MAX[lastCluster, fileObjectRef^.cluster]; PairList.AddPair[clusterMap, refClusterId, refObjectId]; }; }; AppendPathLinks: PROCEDURE[nlinks: CARDINAL, splinetype: SplineDefs.SplineType, cyclic: BOOLEAN, origin: IntegerVec, path: PathRef] = { THROUGH [1 .. nlinks] DO AddLink[splinetype, cyclic, origin, path]; ENDLOOP; }; AddLink: PROCEDURE[splinetype: SplineDefs.SplineType, cyclic: BOOLEAN, origin: IntegerVec, path: PathRef] = TRUSTED { knotword: GFileFormatDefs.GFileKnotWord; knots: SplineDefs.KnotSequence; coeffs: SplineDefs.CoeffsSequence; CoeffsLength: PROCEDURE [coeffs: SplineDefs.CoeffsSequence] RETURNS [CARDINAL] = TRUSTED { RETURN[IF coeffs=NIL THEN 0 ELSE coeffs.length] }; num, j: CARDINAL; fpoint: GFileFormatDefs.GFilePoint; ReadStructure[@knotword, GFileFormatDefs.lGFileKnotWord]; num _ knotword.knotcount; IF num=0 THEN SIGNAL GriffinFileError["bad link"]; SELECT knotword.knottype FROM GFileFormatDefs.typeFD3Knot => { knots _ NEW[SplineDefs.KnotSequenceRec[num]]; FOR j IN [0 .. num) DO ReadStructure[@fpoint, GFileFormatDefs.lGFilePoint]; knots[j] _ SplineDefs.FPCoords[GetReal[fpoint.x], GetReal[fpoint.y]]; ENDLOOP; IF cyclic THEN knots _ MakeCyclicKnots[knots,splinetype]; coeffs _ SplineDefs.MakeSpline[knots,splinetype]; FOR j IN [0..CoeffsLength[coeffs]) DO c: Cubic.Coeffs; c.c0 _ [coeffs[j].t0[SplineDefs.X],coeffs[j].t0[SplineDefs.Y]]; c.c1 _ [coeffs[j].t1[SplineDefs.X],coeffs[j].t1[SplineDefs.Y]]; c.c2 _ [coeffs[j].t2[SplineDefs.X],coeffs[j].t2[SplineDefs.Y]]; c.c3 _ [coeffs[j].t3[SplineDefs.X],coeffs[j].t3[SplineDefs.Y]]; IF inThisView THEN AppendCubic[Cubic.CoeffsToBezier[c], origin, path]; ENDLOOP; }; GFileFormatDefs.typeFD0Knot, GFileFormatDefs.typeFD1Knot, GFileFormatDefs.typeFD2Knot => FOR j IN [0 .. num) DO ReadStructure[@fpoint, GFileFormatDefs.lGFilePoint]; IF inThisView THEN AppendPoint[[GetReal[fpoint.x], GetReal[fpoint.y]], origin, path]; ENDLOOP; ENDCASE => SIGNAL GriffinFileError["bad link"]; }; MakeCyclicKnots: PROCEDURE[knots: SplineDefs.KnotSequence, type: SplineDefs.SplineType] RETURNS[SplineDefs.KnotSequence] = { cycknots: SplineDefs.KnotSequence; numknots: INTEGER _ IF knots=NIL THEN 0 ELSE knots.length; newLength,i: INTEGER; IF numknots <= 0 THEN RETURN[NIL]; SELECT type FROM cyclicUM, cyclicAL, bezier=> newLength _ numknots+1; bspline, crspline=> newLength _ numknots+3; ENDCASE; cycknots _ NEW[SplineDefs.KnotSequenceRec[newLength]]; FOR i IN [0..numknots) DO cycknots[i] _ knots[i]; ENDLOOP; cycknots[numknots] _ cycknots[0]; SELECT type FROM naturalUM => type _ cyclicUM; naturalAL => type _ cyclicAL; bspline => { cycknots[numknots+1] _ cycknots[1]; cycknots[numknots+2] _ cycknots[2]; }; crspline => { cycknots[numknots+1] _ cycknots[1]; cycknots[numknots+2] _ cycknots[2]; }; ENDCASE; RETURN[cycknots]; }; AppendCubic: PROCEDURE[c: Cubic.Bezier, origin: IntegerVec, path: PathRef] = { b0, b1, b2, b3: Vector.Vec; b0 _ XFormPt[c.b0,origin]; b1 _ XFormPt[c.b1,origin]; b2 _ XFormPt[c.b2,origin]; b3 _ XFormPt[c.b3,origin]; IF CGPath.Empty[path] THEN Graphics.MoveTo[path,b0.x,b0.y]; Graphics.CurveTo[path,b1.x,b1.y,b2.x,b2.y,b3.x,b3.y]; }; AppendPoint: PROCEDURE[p: Vector.Vec, origin: IntegerVec, path: PathRef] = { v: Vector.Vec _ XFormPt[p,origin]; IF CGPath.Empty[path] THEN Graphics.MoveTo[path,v.x,v.y] ELSE Graphics.LineTo[path,v.x,v.y]; }; XFormPt: PROC [p: Vector.Vec, origin: IntegerVec] RETURNS [Vector.Vec] = { RETURN[[GriffinToTAPrivate.ScalePressToScreenCoord[p.x]-origin.x, GriffinToTAPrivate.ScalePressToScreenCoord[p.y]-origin.y]]; }; ReverseRelation: PROCEDURE[map: PairList.Relation] RETURNS[PairList.Relation] = { new: PairList.Relation _ PairList.CreateRelation[]; add: PROC[leftPart, rightPart: REF ANY] = { PairList.AddPair[new, leftPart, rightPart]}; IF map=NIL THEN RETURN[map]; PairList.ForAllPairs[map, add]; map _ new; PairList.DestroyRelation[new]; RETURN[map]; }; ReadWord: PROCEDURE RETURNS[CARDINAL] = { high, low: CHARACTER; word: Basics.BytePair; high _ IO.GetChar[diskHandle]; low _ IO.GetChar[diskHandle]; word.high _ LOOPHOLE[high]; word.low _ LOOPHOLE[low]; RETURN[LOOPHOLE[word]]; }; ReadString: PROCEDURE RETURNS[r: ROPE] = { t: REF TEXT; length: CARDINAL; length _ LOOPHOLE[IO.GetChar[diskHandle], CARDINAL]; t _ NEW[TEXT[length]]; IF IO.GetBlock[diskHandle,t,0,length] # length THEN SIGNAL GriffinFileError["Possible disk problem"]; r _ Rope.FromRefText[t]; IF (length+1) MOD 2 # 0 THEN [] _ IO.GetChar[diskHandle]; }; MoveToSector: PROCEDURE[si: GFileFormatDefs.SectorIndex] = { IO.SetIndex[diskHandle, INTEGER[si*PrincOps.bytesPerPage]]; }; ReadStructure: PROCEDURE[p: LONG POINTER, l: CARDINAL] = TRUSTED { from: LONG POINTER; b: REF TEXT _ NEW[TEXT[l*2]]; IF IO.GetBlock[diskHandle, b, 0, 2*l] # 2*l THEN SIGNAL GriffinFileError["Possible disk problem"]; from _ LOOPHOLE[b,LONG POINTER]+2; --start of bytes PrincOpsUtils.LongCOPY[from,l,p]; }; GetReal: PROCEDURE[r: LONG UNSPECIFIED] RETURNS[out: REAL] = TRUSTED { IF realConvert THEN RETURN[RealConvert.Mesa5ToIeee[r]] ELSE RETURN[LOOPHOLE[r]]; }; FixFileName: PROCEDURE[oldname, extension: ROPE] RETURNS [newname:ROPE] = { dotPosition: INTEGER _ Rope.Find[oldname, "."]; IF dotPosition < 0 THEN newname _ Rope.Cat[oldname, extension] ELSE newname _ Rope.Cat[Rope.Substr[oldname, 0, dotPosition], extension]; }; }. ŠGriffinToTAImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Read Griffin files and convert to Tioga Artwork files borrowed liberally from ReadGriffinImpl.mesa and GriffinFile.mesa Rick Beach, February 9, 1985 9:57:42 pm PST Maureen Stone May 5, 1983 4:52 pm now our own data structures control pairs not implemented version 1.4 is the first with the Ieee floating point format. we need to set up to convert the reals for older versions so ForAllPairs in generating objects does so in chronological order private low-level disk access procedures always read an even number of bytes: string length + string chars MOD 2 = 0 Κ ˜šœ™Jšœ Οmœ1™Jšœ žœŸ˜DJšœ žœŸ ˜GJšœžœžœ˜!Jšœžœžœ˜/Jšœžœ žœ˜Jšœ žœžœ˜!Jšœ žœžœ˜&Jšœžœžœ˜%Jšœžœžœ˜,Jšœžœžœ˜(J˜JšœžœŸ ˜˜XJ˜J˜—š œžœž œ žœ˜FJšžœ žœ ˜ J˜-Jšœ2žœžœ ˜LJ˜J˜šžœžœ˜J˜)Jšœžœ˜—J˜8J˜Jšžœ˜Jšžœžœ>˜XJ˜J˜—š œž œ˜!J˜)J˜$J˜%J˜&J˜$J˜'J˜'Jšœžœ˜J˜J˜Jšœ žœ˜J˜Jšœžœ˜J˜J˜J˜—š œž œ˜$J˜"J˜#J˜$J˜"J˜%J˜%Jšœ žœ˜Jšœžœ˜Jšœ žœ˜ J˜J˜—š  œž œ)žœ˜GJ˜(J˜2J˜1J˜,Jšœ*žœ˜3J˜J˜Jšœ)Ÿ˜HJ˜=J˜CJ˜BJšœ™Jšžœ*žœžœ,˜cJ˜šžœžœž˜J˜Jšžœ˜—J˜šžœžœž˜J˜Jšžœ˜—J˜šžœžœ˜J˜Jšžœ˜—J˜J˜—š   œž œžœžœžœ žœ˜QJšžœ˜J˜/Jšœžœ˜šžœžœžœ˜@Jšœ=™=Jšœ9™9šžœžœžœ˜,Jšžœžœ˜—J˜—J˜J˜—š œž œ žœ!˜IJšœžœ˜/š œ žœžœžœžœ˜5Jšœžœ$˜:—J˜+J˜J˜—š  œž œžœ"˜Lšœžœ˜2š œ žœžœžœžœ˜7Jšœžœ&˜<——Jšžœžœ˜AJ˜.J˜J˜—š  œž œ1žœ˜OJšœžœ˜žœ˜|J˜"Jš œ žœžœžœžœžœ˜:Jšœ žœ˜Jšžœžœžœžœ˜"šžœž˜J˜ J˜ J˜ J˜J˜"Jšžœ˜—Jšœ žœ(˜6šžœžœž˜J˜Jšžœ˜—J˜!šžœž˜J˜J˜˜ J˜#J˜#J˜—˜J˜#J˜#J˜—Jšžœ˜—Jšžœ ˜J˜J˜—š  œž œ8˜NJ˜J˜J˜J˜J˜Jšžœžœ!˜;J˜5J˜J˜—š  œž œ6˜LJ˜"Jšžœžœ˜8Jšžœ˜#J˜J˜—š œžœ%žœ˜Jšžœ;˜AJ˜;—J˜J˜—JšœC™CJ˜š œž œžœ˜QJ˜3šœžœžœžœ˜+J˜,—Jšžœžœžœžœ˜J˜J˜ J˜Jšžœ˜ J˜J˜J˜—Jšœ(™(J˜š œž œžœžœ˜)Jšœ ž œ˜Jšœ˜Jšœžœ˜Jšœžœ˜Jšœ žœžœ˜5Jšžœžœ˜J˜J˜—š  œž œžœžœ˜+Jšœžœžœ˜ Jšœžœ˜Jšœ žœžœžœ˜4Jšœžœžœ ˜šžœžœ)˜.Jšžœžœ+˜6—J˜JšœK™KJšžœ žœžœžœ˜9J˜J˜—š  œž œ%˜