GriffinFile
Stone April 30, 1981 1:51 PM
Stone Changed minor version September 30, 1980 1:40 PM
Tiberi January 20, 1980 7:38 PM
implementing module for griffin file creation
NOTE: Strange patch in ReplaceFigure to "cleanup" files with multiple figures
Last Edited by: Stone, March 20, 1984 10:52:10 am PST
Last Edited by: Pier, February 14, 1984 10:18:47 am PST
DIRECTORY
GriffinFileDefs: FROM "GriffinFileDefs",
GFileFormatDefs: FROM "GFileFormatDefs",
GriffinDefs: FROM "GriffinDefs" USING [UserMessage],
GriffinMemoryDefs: FROM "GriffinMemoryDefs",
ControllerDefs: FROM "ControllerDefs",
StyleDefs USING [Style, StyleHandle, Color],
GriffinStyle,
GriffinText USING [GetBoundingBox],
GriffinColor USING [FileColor, ColorFromFileColor, FileColorFromColor],
ObjectDefs
USING [StartObject, ObjectHandle, Object, Link, Trajectory,
ObjectType, ForAllObjects, ObjectProc, OpenCluster,
GetNextClusterID, View, GetCurrentView, EncodeObject],
PointDefs USING [ObjPt, ScrPt, X, Y, ObjPtSequence, ObjPtSequenceRec],
PrincOpsUtils USING [LongCopy],
CubicSplines USING [SplineType],
IO,
FS,
UserCredentials USING [Get],
RealConvert: FROM "RealConvert" USING [Mesa5ToIeee],
BasicTime USING [Now],
GriffinFontDefs USING [FontDescriptor, FontDescriptorHandle],
RelationDefs: FROM "RelationDefs",
Rope USING [ROPE, Length, FromProc, Fetch, Flatten, FromRefText, ToRefText];
GriffinFile:
PROGRAM
IMPORTS
IO,
FS, UserCredentials, Rope, BasicTime,
GriffinMemoryDefs, ControllerDefs, ObjectDefs, GriffinDefs, RelationDefs, RealConvert, PrincOpsUtils, GriffinStyle, GriffinColor, GriffinText
EXPORTS GriffinFileDefs =
BEGIN OPEN GFileFormatDefs, GriffinFileDefs, GriffinMemoryDefs;
---------------------------------------------------------------------------------
GriffinFileError: PUBLIC SIGNAL = CODE;
ROPE: TYPE = Rope.ROPE;
diskHandle: IO.STREAM;
GFileState: TYPE = {notopen, open};
gfileState: GFileState ← notopen;
majorVersion: BYTE = 3;
minorVersion: BYTE = 0;
maxCPairCount: CARDINAL = 2000; -- just for safety
realConvert: BOOLEAN ← FALSE;
version 2.0 is Cedar
version 2.1 is after string fix
version 2.2 is Cedar 5 ?
version 3.0 is cedar 6.0
--------------------------------------------------------------------------
GetReal: PROCEDURE [r: REAL] RETURNS [out: REAL] =
BEGIN
IF realConvert THEN RETURN[RealConvert.Mesa5ToIeee[LOOPHOLE[r]]]
ELSE RETURN[r];
END;
OpenFile:
PUBLIC
PROCEDURE [filename:
ROPE, write:
BOOLEAN ←
FALSE]
RETURNS [
BOOLEAN] =
BEGIN
newfile: BOOLEAN ←FALSE;
username: ROPE;
header: GFileHeader;
j: INTEGER; -- just a loop control variable
IF gfileState # notopen THEN SIGNAL GriffinFileError;
IF write
THEN BEGIN
OPEN header;
len: INTEGER;
diskHandle ←
FS.StreamOpen[fileName: filename, accessOptions: $create, keep: 2 ! FS.Error =>
{
IF error.group=user
AND error.code=$unknownFile
THEN SIGNAL GriffinDefs.UserMessage["unknown file"]
ELSE IF error.group=user
AND error.code=$globalCreation
THEN SIGNAL GriffinDefs.UserMessage["can't write on remote file"]
ELSE SIGNAL GriffinFileError}
];
Zero [@header, lGFileHeader];
majversion ← majorVersion;
minversion ← minorVersion;
createtime ← LOOPHOLE[BasicTime.Now[], LONG CARDINAL];--don't change the interface
numfigs ← 0;
nextsector ← SectorIndex [1];
Reset[diskHandle];
FOR j IN ValidFigRange DO header.figure [j] ← SectorIndex [0]; ENDLOOP;
[username,] ← UserCredentials.Get[];
len ← Rope.Length[username];
creatorname [0] ← LOOPHOLE [len, CHARACTER];
FOR j
IN [1 .. cNameChars]
DO
creatorname [j] ← IF j > len THEN 0C ELSE Rope.Fetch[username,j-1];
ENDLOOP;
len ← Rope.Length[filename];
portfolioname [0] ← LOOPHOLE [len, CHARACTER];
FOR j
IN [1 .. pNameChars]
DO
portfolioname[j] ← IF j > len THEN 0C ELSE Rope.Fetch[filename,j-1];
ENDLOOP;
WriteHeaderAndFlush [@header];
END
ELSE diskHandle ←
FS.StreamOpen[fileName: filename, accessOptions: $read !
FS.Error =>
{
IF error.group=user
AND error.code=$unknownFile
THEN SIGNAL GriffinDefs.UserMessage["unknown file"]
ELSE SIGNAL GriffinFileError}];
gfileState ← open;
RETURN [TRUE];
END;
---------------------------------------------------------------------------------
CloseFile:
PUBLIC
PROCEDURE =
BEGIN
fileheader: GFileHeader;
IF gfileState = notopen THEN RETURN;
ReadHeader [@fileheader];
MoveToSector [fileheader.nextsector];
IO.Close [diskHandle];
gfileState ← notopen;
END;
---------------------------------------------------------------------------------
DeletePortfolio: PUBLIC PROCEDURE = BEGIN
IF gfileState = notopen THEN RETURN;
this procedure should really delete the file, not just truncate it
gfileState ← notopen;
IO.Close[diskHandle];
END;
---------------------------------------------------------------------------------
ReadFigure:
PUBLIC
PROCEDURE =
BEGIN OPEN RelationDefs;
fileheader: GFileHeader;
hcontrol: GFileHardcopyController;
dcontrol: GFileDisplayController;
controlpair: GFileControlPair;
font: GFileFont;
figurename: GFileFigureName;
stylecount, fontcount, objectcount, i, slen, f, s: CARDINAL;
color: StyleDefs.Color;
fd: GriffinFontDefs.FontDescriptorHandle ← CZone.NEW[GriffinFontDefs.FontDescriptor];
clusterMap: Relation;
newStyles, oldStyles: GriffinStyle.StyleSequence;
fontList: GriffinStyle.FontSequence;
fignum: CARDINAL=1; --original plan involved multiple figures in a portfolio. Never used more than 1
IF gfileState # open THEN SIGNAL GriffinFileError;
ReadHeader [@fileheader];
IF fignum > fileheader.numfigs OR fignum = 0 THEN SIGNAL GriffinFileError;
MoveToSector [fileheader.figure [fignum]]; -- go to the right sector
ReadStructure [@figurename, lGFileFigureName];
allocate global string for figure name
name.length ← LOOPHOLE [figurename [0], BYTE];
FOR i IN [1 .. name.length] DO name [i] ← figurename.char [i] ENDLOOP;
ReadStructure [@hcontrol, lGFileHardcopyController];
ReadStructure [@dcontrol, lGFileDisplayController];
BEGIN
OPEN hcontrol;
ControllerDefs.SetHardcopyController [[hxcenter: GetReal[centerx],
hycenter: GetReal[centery], hwidth: GetReal[width],
hheight: GetReal[height],
pressxcenter: presscenterx, pressycenter: presscentery,
hscale: GetReal[scale]]];
END;
BEGIN
OPEN dcontrol;
ControllerDefs.SetDisplayController [[dxcenter: centerx,
dycenter: centery, dwidth: width, dheight: height,
dxscale: GetReal[xscale], dyscale: GetReal[yscale],
dxorigin: GetReal[gridxo],
dyorigin: GetReal[gridyo], dgridsize: gridsize]];
END;
IF dcontrol.numcontrolpairs > maxCPairCount THEN SIGNAL GriffinFileError;
THROUGH [1 .. dcontrol.numcontrolpairs]
DO
OPEN controlpair;
ReadStructure [@controlpair, lGFileControlPair];
color ← [H: hue, V: brightness, S: saturation];
colorpairs are not used but must be read out of the file.
ENDLOOP;
fontcount ← ReadWord [];
fontList ← CZone.NEW[GriffinStyle.FontSequenceRec[fontcount]];
FOR f
IN [0 .. fontcount)
DO
fromProc: SAFE PROC RETURNS [CHAR] = CHECKED {i ← i+1; RETURN[ font.char [i]]};
ReadStructure [@font, lGFileFont];
slen ← LOOPHOLE [font.char [0], BYTE]; -- just a temp
i ← 0;
fd.name ← Rope.FromProc[slen,fromProc];
fd.rotation ← font.rotation;
fd.face ← font.face;
fd.points ← font.points;
fontList[f] ← GriffinStyle.FontFromInternalFont[fd];
ENDLOOP;
stylecount ← ReadWord [];
oldStyles ← GriffinStyle.CreateStyleList[];
newStyles ← CZone.NEW[GriffinStyle.StyleSequenceRec[stylecount]];
FOR s
IN [0 .. stylecount)
DO
newStyles[s] ← ReadStyle [fontList, oldStyles]; --returns a style, reusing duplicates
ENDLOOP;
objectcount ← ReadWord [];
clusterMap ← CreateRelation[];
THROUGH [1 .. objectcount]
DO ReadObject [newStyles, clusterMap]; ENDLOOP;
DestroyRelation[clusterMap];
END;
---------------------------------------------------------------------------------
ReplaceFigure: PUBLIC PROCEDURE [fignum: FigureNumber] RETURNS [BOOLEAN] = BEGIN
Stone April 16, 1980 9:38 PM
figbegin, oldfigend: SectorIndex;
j: CARDINAL;
sectorsadded: INTEGER;
header: GFileHeader;
IF gfileState # open THEN SIGNAL GriffinFileError;
ReadHeader [@header];
IF header.numfigs = 0 THEN RETURN[AddFigure[fignum]];
IF fignum = 0 OR fignum > header.numfigs THEN SIGNAL GriffinFileError;
this is a cleanup proc for the bug that was adding figures instead of replacing them
it assumes there is no correct way to have multiple figures in a portfolio
IF header.numfigs > 1 THEN BEGIN
fig: FigureNumber ← header.numfigs;
UNTIL fig = 1 DO
DeleteFigure[fig];
fig ← fig-1;
ENDLOOP;
ReadHeader [@header];
END;
header.minversion ← minorVersion;
header.createtime ← LOOPHOLE[BasicTime.Now[], LONG CARDINAL];--don't change the interface
figbegin ← header.figure [fignum]; -- where figure begins
oldfigend ← header.figure [fignum+1]; --where figure ends, or 0
IF oldfigend = 0 THEN BEGIN -- last fig in file, no problem
MoveToSector [figbegin];
header.nextsector ← WriteFigureContents [];
END
ELSE BEGIN
MoveToSector [header.nextsector];
sectorsadded ← WriteFigureContents [] - header.nextsector -
(oldfigend - figbegin);
MoveSectors [oldfigend, sectorsadded, header.nextsector];
MoveToSector [figbegin];
[] ← WriteFigureContents [];
header.nextsector ← SectorIndex [header.nextsector + sectorsadded];
FOR j IN (fignum .. header.numfigs] DO
header.figure [j] ← SectorIndex [header.figure [j] +
sectorsadded];
ENDLOOP;
END;
WriteHeaderAndFlush [@header];
RETURN [TRUE];
END;
---------------------------------------------------------------------------------
DeleteFigure: PUBLIC PROCEDURE [fignum: FigureNumber] = BEGIN
figbegin, nextfigbegin: SectorIndex;
sectordelta: INTEGER;
i: CARDINAL;
header: GFileHeader;
IF gfileState # open THEN SIGNAL GriffinFileError;
ReadHeader [@header];
figbegin ← header.figure [fignum];
nextfigbegin ← header.figure [fignum+1];
IF fignum = 0 OR fignum > header.numfigs THEN SIGNAL GriffinFileError;
IF nextfigbegin = 0 THEN header.nextsector ← figbegin ELSE
BEGIN -- wasn't last fig in file
sectordelta ← figbegin - header.figure [fignum+1];
MoveSectors [nextfigbegin, sectordelta, header.nextsector];
header.nextsector ← SectorIndex [header.nextsector + sectordelta];
FOR i IN [fignum .. header.numfigs) DO header.figure [i] ←
SectorIndex [header.figure [i+1] + sectordelta];
ENDLOOP;
header.figure [header.numfigs] ← SectorIndex [0];
END;
header.numfigs ← header.numfigs - 1;
WriteHeaderAndFlush [@header];
END;
---------------------------------------------------------------------------------
WriteFigure: PUBLIC PROCEDURE = BEGIN
Stone April 16, 1980 9:38 PM
figbegin: SectorIndex;
i, figlength: CARDINAL;
header: GFileHeader;
fignum: CARDINAL=1; --was a plan involving multiple figures, now canceled
IF gfileState # open THEN SIGNAL GriffinFileError;
ReadHeader [@header];
IF fignum > header.numfigs + 1 THEN SIGNAL GriffinDefs.UserMessage["Invalid file."];
figbegin ← header.figure [fignum];
IF figbegin = 0 THEN figbegin ← header.figure [fignum] ← SectorIndex [1];
MoveToSector [header.nextsector];
figlength ← WriteFigureContents [] - header.nextsector;
FOR i
DECREASING
IN [fignum .. header.numfigs]
DO
header.figure [i+1] ← SectorIndex [header.figure [i] +figlength];
ENDLOOP;
MoveSectors [figbegin, figlength, header.nextsector];
header.nextsector ← SectorIndex [header.nextsector + figlength];
IF header.numfigs >= fignum
THEN
BEGIN
-- wasn't last fig, write it again
MoveToSector [figbegin];
[] ← WriteFigureContents [];
END;
header.numfigs ← header.numfigs + 1;
WriteHeaderAndFlush [@header];
END;
---------------------------------------------------------------------------------
ReadHeader:
PROCEDURE [h:
LONG
POINTER
TO GFileHeader] =
BEGIN
version,currentVersion: CARDINAL;
Reset[diskHandle];
ReadStructure [h, lGFileHeader];
realConvert ← FALSE;
version ← h.majversion*10+h.minversion;
currentVersion ← majorVersion*10+minorVersion;
version 1.4 is the first with the Ieee floating point format.
we need to set up to convert the reals for older versions
IF version < 14 THEN realConvert ← TRUE;
IF version
NOT
IN [10..currentVersion]
THEN {
IO.Close[diskHandle];
gfileState ← notopen;
GriffinDefs.UserMessage["Incorrect file format."];
};
END;
---------------------------------------------------------------------------------
WriteHeaderAndFlush:
PROCEDURE [h:
LONG
POINTER
TO GFileHeader] =
BEGIN
Reset[diskHandle];
WriteStructure [h, lGFileHeader];
IO.Flush [diskHandle];
END;
---------------------------------------------------------------------------------
WriteFigureContents:
PROCEDURE
RETURNS [nextfree: SectorIndex] =
BEGIN
hcontroller: GFileHardcopyController;
dcontroller: GFileDisplayController;
figname: GFileFigureName;
hc: ControllerDefs.HardcopyController; -- temp
dc: ControllerDefs.DisplayController; -- temp
count: CARDINAL;
fonts: GriffinStyle.FontSequence;
styles: GriffinStyle.StyleSequence;
doWrite: ObjectDefs.ObjectProc = TRUSTED {WriteObject[obj, styles]};
CountObject: ObjectDefs.ObjectProc =
TRUSTED
BEGIN
SELECT obj.objectType
FROM
shape,caption => count ← count+1; ENDCASE;
END;
CountPair: SAFE PROC [h, s, v: [0 .. 255], grey: [0 .. 255]] = TRUSTED { count ← count+1 };
Zero [@figname, lGFileFigureName];
WriteStructure [@figname, lGFileFigureName];
Zero [@hcontroller, lGFileHardcopyController];
BEGIN
OPEN ControllerDefs, hcontroller;
[hxcenter: centerx, hycenter: centery, hwidth: width,
hheight: height, pressxcenter: presscenterx, pressycenter: presscentery,
hscale: scale] ← hc ← ReadHardcopyController [];
END;
Zero [@dcontroller, lGFileDisplayController];
BEGIN
OPEN ControllerDefs, dcontroller;
[dxcenter: centerx, dycenter: centery, dwidth: width,
dheight: height, dxscale: xscale, dyscale: yscale, dxorigin: gridxo,
dyorigin: gridyo, dgridsize: gridsize] ← dc ←
ReadDisplayController [];
END;
WriteStructure [@hcontroller, lGFileHardcopyController];
count ← 0;
ControllerDefs.ForAllControlPairs [CountPair]; dcontroller.numcontrolpairs ← count;
WriteStructure [@dcontroller, lGFileDisplayController];
ControllerDefs.ForAllControlPairs [WriteControlPair];
styles ← GriffinStyle.CreateStyleList[];
IF styles#
NIL
THEN {
--empty file if styles=NIL
fonts ← GriffinStyle.CreateFontList[styles];
WriteWord[fonts.length];
FOR i:
NAT
IN [0..fonts.length)
DO
WriteFont[GriffinStyle.InternalFontFromFont[fonts[i]]];
ENDLOOP;
WriteWord[styles.length];
FOR i: NAT IN [0..styles.length) DO WriteStyle[styles[i], fonts]; ENDLOOP;
count ← 0; ObjectDefs.ForAllObjects [CountObject]; WriteWord [count];
ObjectDefs.ForAllObjects [doWrite];
};
nextfree ← ZeroRestOfSector []
END;
---------------------------------------------------------------------------------
WriteControlPair:
SAFE PROCEDURE [h, s, v: [0 .. 255], grey:
CARDINAL [0 .. 255]] =
TRUSTED BEGIN
This information is never really used
cp: GFileControlPair;
Zero [@cp, lGFileControlPair];
cp.hue ← h;
cp.saturation ← s;
cp.brightness ← v;
cp.greytouse ← grey;
WriteStructure [@cp, lGFileControlPair];
END;
---------------------------------------------------------------------------------
WriteFont:
PROCEDURE [fd: GriffinFontDefs.FontDescriptorHandle] =
BEGIN
j,len: INTEGER;
font: GFileFont;
Zero [@font, lGFileFont];
font.points ← fd.points;
font.face ← fd.face;
font.rotation ← fd.rotation;
len ← Rope.Length[fd.name];
font.char [0] ← LOOPHOLE [len, CHARACTER];
FOR j
IN [1.. fontChars]
DO
font.char[j] ← IF j<=len THEN Rope.Fetch[fd.name,j-1] ELSE 0C;
ENDLOOP;
WriteStructure [@font, lGFileFont];
END;
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
WriteStyle:
PROCEDURE [style: StyleDefs.StyleHandle, fonts: GriffinStyle.FontSequence] =
BEGIN
OPEN StyleDefs, style;
fstyle: GFileStyle;
fcolor: GriffinColor.FileColor;
j,len: INTEGER;
Zero [@fstyle, lGFileStyle];
fcolor ← GriffinColor.FileColorFromColor[style.color];
fstyle.hue ← fcolor.hue;
fstyle.saturation ← fcolor.saturation;
fstyle.brightness ← fcolor.brightness;
fstyle.dashedness ←
SELECT dashed
FROM
undashed => typeUnDashed,
dash1 => typeDash1,
dash2 => typeDash2,
dash3 => typeDash3,
dash4 => typeDash4,
dash5 => typeDash5,
ENDCASE => typeUnDashed;
fstyle.send ←
SELECT firstend.type
FROM
round => typeRoundEnd,
cyclic => typeCyclicEnd,
flat => typeFlatEnd,
angled => typeAngledEnd,
ENDCASE => typeRoundEnd;
fstyle.eend ←
SELECT lastend.type
FROM
round => typeRoundEnd,
cyclic => typeCyclicEnd,
flat => typeFlatEnd,
angled => typeAngledEnd,
ENDCASE => typeRoundEnd;
fstyle.bdx ← firstend.dx;
fstyle.bdy ← firstend.dy;
fstyle.ba ← firstend.a;
fstyle.bb ← firstend.b;
fstyle.bc ← firstend.c;
fstyle.edx ← lastend.dx;
fstyle.edy ← lastend.dy;
fstyle.ea ← lastend.a;
fstyle.eb ← lastend.b;
fstyle.ec ← lastend.c;
fstyle.thickness ← width;
fstyle.junction ←
SELECT junctiontype
FROM
round => typeRoundJunction,
square => typeSquareJunction,
angled => typeAngledJunction,
ENDCASE => typeRoundJunction;
fcolor ← GriffinColor.FileColorFromColor[style.fillcolor];
fstyle.ahue ← fcolor.hue;
fstyle.asaturation ← fcolor.saturation;
fstyle.abrightness ← fcolor.brightness;
fstyle.afilled ← filled;
fstyle.aoutlined ← outlined;
fstyle.fontid ← GriffinStyle.NumberOfFont[style.font, fonts];
fcolor ← GriffinColor.FileColorFromColor[style.backgndcolor];
fstyle.bhue ← fcolor.hue;
fstyle.bsaturation ← fcolor.saturation;
fstyle.bbrightness ← fcolor.brightness;
fstyle.background ← fillbackgnd;
fstyle.anchor ←
SELECT anchor
FROM
left => typeLeftAnchor,
center => typeCenterAnchor,
right => typeRightAnchor,
ENDCASE => typeLeftAnchor;
fstyle.torient ←
SELECT stringRotation
FROM
or0 => typeRot0,
or90 => typeRot90,
or180 => typeRot180,
or270 => typeRot270,
ENDCASE => typeRot0;
len ← Rope.Length[name];
fstyle.stylename [0] ← LOOPHOLE [len, CHARACTER];
FOR j
IN [1 .. sNameChars]
DO
fstyle.stylename [j] ← IF j > len THEN 0C ELSE Rope.Fetch[name, j-1];
ENDLOOP;
WriteStructure [@fstyle, lGFileStyle];
END;
---------------------------------------------------------------------------------
WriteObject: PROCEDURE [obj: ObjectDefs.ObjectHandle, styles: GriffinStyle.StyleSequence] =
BEGIN OPEN ObjectDefs;
fobject: GFileObject;
fcaptiontrailer: GFileCaptionTrailer;
flinks: REF Link;
fakelink: REF Link ← CZone.NEW[Link ← [link: NIL, degree: D3, knots: NIL]];
flinkcount: CARDINAL;
SELECT obj.objectType
FROM
shape,caption => NULL; --do these
ENDCASE => RETURN; --ignore the rest
Zero [@fobject, lGFileObject];
Zero [@fcaptiontrailer, lGFileCaptionTrailer];
fobject.hidewindow ← obj.view # ObjectDefs.GetCurrentView[];
fobject.visible ←
SELECT obj.cull
FROM
inside => typeWhollyVisible,
outside => typeNotVisible,
partial => typePartiallyVisible,
ENDCASE => typePartiallyVisible;
fobject.style ← GriffinStyle.NumberOfStyle [obj.style, styles];
fobject.cluster ← obj.cluster;
fobject.bleft ← obj.tl [PointDefs.X];
fobject.bbottom ← obj.br [PointDefs.Y];
fobject.bright ← obj.br [PointDefs.X];
fobject.btop ← obj.tl [PointDefs.Y];
WITH object: obj SELECT FROM
shape =>
BEGIN OPEN CubicSplines;
fobject.objtype ← IF object.closed THEN typeAreaObject ELSE typeCurveObject;
fobject.splinetype ←
SELECT object.trajectory.splineType
FROM
SplineType [naturalUM] => typeNUMSpline,
SplineType [cyclicUM] => typeCUMSpline,
SplineType [naturalAL] => typeNALSpline,
SplineType [cyclicAL] => typeCALSpline,
SplineType [bezier] => typeBEZSpline,
SplineType [bsplineInterp] => typeBSISpline,
SplineType [bspline] => typeBSpline,
SplineType [crspline] => typeCRSpline,
ENDCASE => typeCRSpline;
WITH traj: object.trajectory
SELECT
FROM
linked =>
BEGIN
fobject.trajtype ← typeLinkedTraj;
flinkcount ← CountLinks [traj.links];
flinks ← traj.links;
END;
cyclic =>
BEGIN
fobject.trajtype ← typeCSTraj;
flinkcount ← 1;
flinks ← fakelink;
fakelink.knots ← traj.knots;
END;
ENDCASE => SIGNAL GriffinFileError;
WriteStructure [@fobject, lGFileObject];
WriteWord [flinkcount];
UNTIL flinks = NIL DO WriteLink [flinks]; flinks ← flinks.link; ENDLOOP;
END;
caption =>
BEGIN
fobject.objtype ← typeCaptionObject;
WriteStructure [@fobject, lGFileObject];
fcaptiontrailer.xanchor ← object.p0 [PointDefs.X];
fcaptiontrailer.yanchor ← object.p0 [PointDefs.Y];
WriteStructure [@fcaptiontrailer, lGFileCaptionTrailer];
WriteString [object.text];
END;
ENDCASE => ERROR;
END;
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
CountLinks: PROCEDURE [links: REF ObjectDefs.Link] RETURNS [count: CARDINAL] = BEGIN
count ← 0;
UNTIL links = NIL DO links ← links.link; count ← count + 1; ENDLOOP;
RETURN;
END;
---------------------------------------------------------------------------------
WriteLink: PROCEDURE [link: REF ObjectDefs.Link] = BEGIN
knotword: GFileKnotWord;
fpoint: GFilePoint;
freal: GFileReal;
j: CARDINAL;
Zero [@knotword, lGFileKnotWord];
Zero [@fpoint, lGFilePoint];
Zero [@freal, lGFileReal];
knotword.knotcount ← link.knots.length;
knotword.knottype ←
SELECT link.degree
FROM
D0 => typeFD0Knot,
D1 => typeFD1Knot,
D2 => typeFD2Knot,
D3 => typeFD3Knot,
ENDCASE => typeFD3Knot;
WriteStructure [@knotword, lGFileKnotWord];
FOR j
IN [0 .. knotword.knotcount)
DO
fpoint.x ← link.knots [j] [PointDefs.X];
fpoint.y ← link.knots [j] [PointDefs.Y];
WriteStructure [@fpoint, lGFilePoint];
ENDLOOP;
END;
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
ReadStyle: PROCEDURE [fonts: GriffinStyle.FontSequence, styles: GriffinStyle.StyleSequence] RETURNS [StyleDefs.StyleHandle] =
BEGIN OPEN StyleDefs;
thisstyle: StyleHandle ← CZone.NEW[Style];
fstyle: GFileStyle;
ReadStructure [@fstyle, lGFileStyle];
BEGIN OPEN thisstyle;
color ← GriffinColor.ColorFromFileColor[[fstyle.hue, fstyle.saturation, fstyle.brightness]];
dashed ←
SELECT fstyle.dashedness
FROM
typeUnDashed => undashed,
ENDCASE => undashed;
firstend.type ←
SELECT fstyle.send
FROM
typeRoundEnd => round,
typeCyclicEnd => cyclic,
typeFlatEnd => flat,
typeAngledEnd => angled,
ENDCASE => round; -- should be an error
lastend.type ←
SELECT fstyle.eend
FROM
typeRoundEnd => round,
typeCyclicEnd => cyclic,
typeFlatEnd => flat,
typeAngledEnd => angled,
ENDCASE => round; -- should be an error
firstend.dx ← GetReal[fstyle.bdx];
firstend.dy ← GetReal[fstyle.bdy];
firstend.a ← GetReal[fstyle.ba];
firstend.b ← GetReal[fstyle.bb];
firstend.c ← GetReal[fstyle.bc];
lastend.dx ← GetReal[fstyle.edx];
lastend.dy ← GetReal[fstyle.edy];
lastend.a ← GetReal[fstyle.ea];
lastend.b ← GetReal[fstyle.eb];
lastend.c ← GetReal[fstyle.ec];
width ← GetReal[fstyle.thickness];
junctiontype ←
SELECT fstyle.junction
FROM
typeRoundJunction => round,
typeSquareJunction => square,
typeAngledJunction => angled,
ENDCASE => round;
fillcolor ← GriffinColor.ColorFromFileColor[[fstyle.ahue, fstyle.asaturation, fstyle.abrightness]];
filled ← fstyle.afilled;
outlined ← fstyle.aoutlined;
font ← fonts[fstyle.fontid-1]; --the first font is font number 1
backgndcolor ← GriffinColor.ColorFromFileColor[[fstyle.bhue, fstyle.bsaturation, fstyle.bbrightness]];
fillbackgnd ← fstyle.background;
anchor ←
SELECT fstyle.anchor
FROM
typeLeftAnchor => left,
typeCenterAnchor => center,
typeRightAnchor => right,
ENDCASE => left; -- should be an error
stringRotation ←
SELECT fstyle.torient
FROM
typeRot0 => or0,
typeRot90 => or90,
typeRot180 => or180,
typeRot270 => or270,
ENDCASE => or0; -- should be an error
stringType ← GriffinStyle.ComputeStringType[stringRotation, font];
END;
{
--an attempt here to avoid the proliferation of identical styles
test: StyleHandle ← GriffinStyle.FindEquivalentStyle[thisstyle, styles];
IF test#NIL THEN thisstyle ← test
ELSE thisstyle.name ← GriffinStyle.NextName[]; --change the name to reflect current scope
};
namelength ← LOOPHOLE [fstyle.stylename [0], BYTE];
BEGIN
fromProc: PROC RETURNS [CHAR] = CHECKED {j ← j+1; RETURN[fstyle.stylename[j]]};
j ← 0;
name ← Rope.FromProc[namelength,fromProc];
END;
RETURN[thisstyle];
END;
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
ReadObject: PROCEDURE[styles: GriffinStyle.StyleSequence, clusterMap: RelationDefs.Relation] =
BEGIN OPEN ObjectDefs;
newobject: ObjectHandle;
fileobject: GFileObject;
fcaptiontrailer: GFileCaptionTrailer;
tl, br: PointDefs.ScrPt;
splinetype: CubicSplines.SplineType;
nlinks: CARDINAL;
ptr: REF Link;
xptr: REF Link;
currentView: ObjectDefs.View ← ObjectDefs.GetCurrentView[];
otherView: ObjectDefs.View
← IF currentView=main THEN alternate ELSE main;
ReadStructure [@fileobject, lGFileObject];
SELECT fileobject.objtype
FROM
typeAreaObject, typeCurveObject =>
newobject← StartObject[shape];
typeCaptionObject =>
newobject← StartObject[caption];
typeTokenObject =>
newobject← StartObject[token];
ENDCASE => SIGNAL GriffinFileError;
newobject.style ← styles[fileobject.style-1]; --the first style is number 1
IF fileobject.cluster <= ObjectDefs.OpenCluster
THEN newobject.cluster ← fileobject.cluster
ELSE
BEGIN
cluster: CARDINAL ← RelationDefs.Right[clusterMap, fileobject.cluster];
IF cluster = RelationDefs.notFound
THEN
BEGIN
cluster ← ObjectDefs.GetNextClusterID[];
RelationDefs.AddPair[clusterMap, fileobject.cluster, cluster];
END;
newobject.cluster ← cluster;
END;
newobject.view ←
IF fileobject.hidewindow
THEN otherView
ELSE currentView;
newobject.cull ←
SELECT fileobject.visible
FROM
typeNotVisible => outside,
typePartiallyVisible => partial,
typeWhollyVisible => inside,
ENDCASE => partial;
tl [PointDefs.X] ← fileobject.bleft; tl [PointDefs.Y] ← fileobject.btop;
br [PointDefs.X] ← fileobject.bright; br [PointDefs.Y] ← fileobject.bbottom;
newobject.tl ← tl; newobject.br ← br;
WITH newobject
SELECT
FROM
object:
REF shape ObjectDefs.Object =>
BEGIN OPEN CubicSplines;
object.closed ← fileobject.objtype = typeAreaObject;
splinetype ←
SELECT fileobject.splinetype
FROM
typeNUMSpline => SplineType [naturalUM],
typeCUMSpline => SplineType [cyclicUM],
typeNALSpline => SplineType [naturalAL],
typeCALSpline => SplineType [cyclicAL],
typeBEZSpline => SplineType [bezier],
typeBSISpline => SplineType [bsplineInterp],
typeBSpline => SplineType [bspline],
typeCRSpline => SplineType [crspline],
ENDCASE => SplineType [bspline];
SELECT fileobject.trajtype
FROM
typeLinkedTraj =>
BEGIN
nlinks ← ReadWord [];
IF nlinks =0 THEN object.trajectory ← CZone.NEW[Trajectory ← [splinetype, linked [NIL]]]
ELSE
BEGIN
ptr ← NewLink [];
object.trajectory ← CZone.NEW[Trajectory ← [splinetype, linked [ptr]]];
THROUGH (1..nlinks] DO ptr←ptr.link←NewLink[] ENDLOOP;
END;
END;
typeCSTraj =>
BEGIN
IF ReadWord [] # 1 THEN SIGNAL GriffinFileError;
xptr ← NewLink [];
object.trajectory ← CZone.NEW[Trajectory ← [splinetype, cyclic [xptr.knots]]];
END;
ENDCASE => SIGNAL GriffinFileError;
ObjectDefs.EncodeObject[object];
END;
object:
REF caption ObjectDefs.Object =>
BEGIN
ReadStructure [@fcaptiontrailer, lGFileCaptionTrailer];
object.p0 [PointDefs.X] ← GetReal[fcaptiontrailer.xanchor];
object.p0 [PointDefs.Y] ← GetReal[fcaptiontrailer.yanchor];
object.text ← ReadString [];
[object.tl, object.br] ← GriffinText.GetBoundingBox[object.text, object.style, object.p0];
END;
ENDCASE;
newobject.validEncoding ← TRUE;
END;
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
NewLink:
PROCEDURE
RETURNS [lin:
REF ObjectDefs.Link] =
BEGIN
OPEN ObjectDefs;
knotword: GFileKnotWord;
knots: PointDefs.ObjPtSequence;
num, j: CARDINAL;
fpoint: GFilePoint;
lin ← CZone.NEW [Link];
ReadStructure [@knotword, lGFileKnotWord];
num ← knotword.knotcount;
SELECT knotword.knottype FROM
typeFD0Knot, typeFD1Knot, typeFD2Knot, typeFD3Knot =>
BEGIN
knots ← CZone.NEW[PointDefs.ObjPtSequenceRec[num]];
lin^ ← Link [
NIL, (
SELECT knotword.knottype
FROM
typeFD0Knot => D0,
typeFD1Knot => D1,
typeFD2Knot => D2,
typeFD3Knot => D3,
ENDCASE => D1), knots];
FOR j
IN [0 .. num)
DO
ReadStructure [@fpoint, lGFilePoint];
knots [j] ← PointDefs.ObjPt[GetReal[fpoint.x], GetReal[fpoint.y]];
ENDLOOP;
END;
ENDCASE => SIGNAL GriffinFileError;
END;
---------------------------------------------------------------------------------
private low-level disk access procedures
---------------------------------------------------------------------------------
WriteWord:
PROCEDURE [word:
CARDINAL] =
BEGIN
bytes: TWOBYTES ← LOOPHOLE[word];
IO.PutChar[diskHandle,bytes.high];
IO.PutChar[diskHandle,bytes.low];
END;
---------------------------------------------------------------------------------
ReadWord:
PROCEDURE
RETURNS [
CARDINAL] =
BEGIN
word: TWOBYTES;
word.high ← IO.GetChar[diskHandle];
word.low ← IO.GetChar[diskHandle];
RETURN[LOOPHOLE[word]];
END;
---------------------------------------------------------------------------------
TWOBYTES: TYPE = MACHINE DEPENDENT RECORD [high: CHARACTER, low: CHARACTER];
WriteString:
PROCEDURE [s:
ROPE] =
BEGIN
len: CARDINAL ← Rope.Length[s];
IO.PutChar[diskHandle,LOOPHOLE [len, CHARACTER]];
IO.PutBlock[diskHandle,Rope.ToRefText[Rope.Flatten[s]]];
IF (len+1) MOD 2 # 0 THEN IO.PutChar[diskHandle,0C];
END;
---------------------------------------------------------------------------------
stringHack: BOOLEAN ← FALSE; --for the old bug in WriteString
ReadString:
PROCEDURE
RETURNS [s:
ROPE] =
BEGIN
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;
s ← Rope.FromRefText[t];
always read an even number of bytes: string length + string chars MOD 2 = 0
IF (length+1) MOD 2 # 0 THEN IF ~stringHack THEN [] ← IO.GetChar[diskHandle];
END;
---------------------------------------------------------------------------------
ZeroRestOfSector:
PROCEDURE
RETURNS [SectorIndex] =
BEGIN
UNTIL IO.GetIndex [diskHandle] MOD 512 = 0 DO WriteWord [0] ENDLOOP;
RETURN [SectorIndex [IO.GetIndex [diskHandle]/512]];
END;
---------------------------------------------------------------------------------
MoveToSector:
PROCEDURE [si: SectorIndex] =
BEGIN
IO.SetIndex [diskHandle, LONG[si.sector]*512];
END;
Reset:
PROCEDURE [d:
IO.
STREAM] =
BEGIN
IO.SetIndex [d, 0];
END;
---------------------------------------------------------------------------------
ReadStructure:
PROCEDURE [p:
LONG
POINTER, l:
CARDINAL] =
BEGIN
block: IO.UnsafeBlock ← [base: LOOPHOLE[p], startIndex: 0, count: l*2];
IF IO.UnsafeGetBlock [diskHandle, block] # l*2 THEN SIGNAL GriffinFileError;
END;
---------------------------------------------------------------------------------
WriteStructure:
PROCEDURE [p:
LONG
POINTER, l:
CARDINAL] =
BEGIN
block: IO.UnsafeBlock ← [base: LOOPHOLE[p], startIndex: 0, count: l*2];
IO.UnsafePutBlock [diskHandle, block];
END;
---------------------------------------------------------------------------------
MoveSectors:
PROCEDURE [source: SectorIndex, dist:
INTEGER, oldfileend: SectorIndex] =
BEGIN
j: CARDINAL;
sector: GFileSector;
p: LONG POINTER TO GFileSector = @sector;
block: IO.UnsafeBlock ← [base: LOOPHOLE[p], startIndex: 0, count: 512];
IF dist < 0
THEN
FOR j
DECREASING
IN [source .. oldfileend)
DO
MoveToSector [SectorIndex [j]];
IF IO.UnsafeGetBlock[diskHandle, block] # 512 THEN SIGNAL GriffinFileError;
MoveToSector [SectorIndex [j+dist]];
IO.UnsafePutBlock[diskHandle, block];
ENDLOOP
ELSE
FOR j
IN [source .. oldfileend)
DO
MoveToSector [SectorIndex [j]];
IF IO.UnsafeGetBlock[diskHandle, block] # 512 THEN SIGNAL GriffinFileError;
MoveToSector [SectorIndex [j+dist]];
IO.UnsafePutBlock[diskHandle, block];
ENDLOOP;
END;
-----------------------------------------------------------------
Zero:
PROC [block:
LONG
POINTER, length:
CARDINAL] = {
block^ ← 0;
PrincOpsUtils.LongCopy[from: block, to: block+1, nwords: length-1];
};
END.