<> <> <> DIRECTORY FileIO USING [Open, OpenFailed], IPEncodingOut, IPXeroxEncoding, IO USING [Close, PutChar], Inline USING [BITSHIFT], Real USING [Fix], Rope USING [ActionType, Fetch, Length, Map, MaxLen, ROPE], Ieee USING [Ext, Unpack]; IPEncodingOutImpl: CEDAR PROGRAM IMPORTS FileIO, Ieee, Inline, IO, IPEncodingOut, Real, Rope EXPORTS IPEncodingOut = BEGIN OPEN IPEncodingOut, IPX: IPXeroxEncoding; OpenOutputMaster: PUBLIC PROCEDURE[name: Rope.ROPE] RETURNS [h: Handle] = { h _ Handle[FileIO.Open[name, overwrite ! FileIO.OpenFailed => CHECKED {ERROR Error[FileNotAvailable]}]]; h.WriteInterpressHeader[]; }; CloseMaster: PUBLIC PROCEDURE[h: Handle] = { h.Close[]; }; AppendOp: PUBLIC PROCEDURE[h: Handle, op: IPX.EncodingValue] = { val: CARDINAL _ LOOPHOLE[op]; IF val <= 31 THEN h.AppendByte[128+val] ELSE { h.AppendByte[160+val/256]; h.AppendByte[val MOD 256]; }; }; AppendByte: PUBLIC PROCEDURE[h: Handle, val: CARDINAL] = { h.PutChar[LOOPHOLE[val, CHAR]]; }; AppendSequenceDescriptor: PUBLIC PROCEDURE[h: Handle, type: IPX.SequenceType, length: NAT] = { val: CARDINAL _ LOOPHOLE[type]; IF length < 0 OR length > 16777215 THEN EncodingRangeError[]; IF length < 255 THEN { h.AppendByte[192+val]; h.AppendByte[length]; } ELSE { h.AppendByte[224+val]; h.AppendInt[length, 3]; }; }; AppendString: PUBLIC PROCEDURE[h: Handle, length: NAT, proc: PROC RETURNS[c: [0..255]]] = { i: NAT; h.AppendSequenceDescriptor[sequenceString, length]; FOR i IN [0..length) DO h.AppendByte[proc[]]; ENDLOOP; }; AppendRope: PUBLIC PROCEDURE [h: Handle, rope: Rope.ROPE, start: INT _ 0, len: INT _ Rope.MaxLen] = { length: INT _ MIN[len, rope.Length[]-start]; index: INT; BlowIfEscape: PROCEDURE [c: CHAR] RETURNS [BOOL] = {RETURN [c = 377C];}; IF Rope.Map[rope, start, len, LOOPHOLE[BlowIfEscape, Rope.ActionType]] OR (length = 0) THEN ERROR Error[RopeEncodingError] ELSE { h.AppendSequenceDescriptor[sequenceString, length]; FOR index IN [start..start+length) DO h.AppendByte[LOOPHOLE[rope.Fetch[index], CARDINAL]]; ENDLOOP; }; }; AppendReal: PUBLIC PROCEDURE[h: Handle, n: REAL] = { f: INT; i: INT; ex: INTEGER; e: Ieee.Ext _ Ieee.Unpack[n]; --UnPack returns frac and exp : n = frac*2^(exp-31) not signed. <<-- adjust sign on mantissa and shift down to get 24 bits of mantissa.>> f _ IF e.det.sign THEN -(e.frac.lc/256) ELSE e.frac.lc/256; IF (e.exp >= 0) AND (e.exp <= 25) AND (n = (i_Real.Fix[n])) THEN h.AppendInteger[i] -- number is vanilla integer ELSE { ex _ e.exp-23; --adjust exponent so that mantissa is integer. IF ex < 0 THEN h.Append2Rational[f, ABS[ex]] -- must divide integer by power of 2. ELSE h.AppendLongInteger[f, ex] -- must add extra bits to integer. }; }; AppendInteger: PUBLIC PROCEDURE[h: Handle, i: INT] = { bn: CARDINAL; IF i IN [-4000..28767] THEN h.AppendInt[4000+i, 2] ELSE { bn _ BytesInInteger[i]; h.AppendSequenceDescriptor[sequenceInteger, bn]; h.AppendInt[i, bn]; }; }; AppendRational: PUBLIC PROCEDURE [h: Handle, i, j: INT] = { c, bn, bd: CARDINAL; bn _ BytesInInteger[i]; bd _ BytesInInteger[j]; c _ MAX[bn,bd]; h.AppendSequenceDescriptor[sequenceRational, 2*c]; h.AppendInt[i, c]; h.AppendInt[j, c]; }; Append2Rational: PUBLIC PROCEDURE [h: Handle, i: INT, e: INTEGER] = { d, c, bn, bd: CARDINAL; j: INT _ i; d _ 0; <<-- right shift off zeros and decrement byte count of denom.>> IF j = 0 THEN { h.AppendInteger[0]; RETURN; }; UNTIL j MOD 256 # 0 DO j _ j/256; d _ d+1; ENDLOOP; bn _ BytesInInteger[j]; bd _ e/8+1-d; c _ MAX[bn,bd]; h.AppendSequenceDescriptor[sequenceRational, 2*c]; h.AppendInt[j, c]; h.Append2Int[e-8*d, c]; }; AppendLongInteger: PUBLIC PROCEDURE [h: Handle, f: INT, e: CARDINAL] = { bn, bt: INTEGER; i, j: INT; i _ e MOD 8; j _ f*LOOPHOLE[Inline.BITSHIFT[1,i], INTEGER]; bn _ BytesInInteger[j]; bt _ e/8; h.AppendSequenceDescriptor[sequenceInteger, bn+bt]; h.AppendInt[j, bn]; THROUGH [0..bt) DO h.AppendByte[0]; ENDLOOP; }; AppendInt: PUBLIC PROCEDURE [h: Handle, i: INT, c: CARDINAL] = { a: PACKED ARRAY [0..3] OF [0..255]; bi: CARDINAL _ BytesInInteger[i]; IF bi > c THEN EncodingRangeError[]; THROUGH [0..c-bi) DO IF i < 0 THEN h.AppendByte[255] ELSE h.AppendByte[0];--store leading 1's or 0's ENDLOOP; a _ LOOPHOLE[i]; IF bi > 3 THEN h.AppendByte[a[2]]; IF bi > 2 THEN h.AppendByte[a[3]]; IF bi > 1 THEN h.AppendByte[a[0]]; IF bi > 0 THEN h.AppendByte[a[1]]; }; Append2Int: PUBLIC PROCEDURE [h: Handle, e: CARDINAL, c: CARDINAL] = { bi: CARDINAL _ e/8+1; IF bi > c THEN EncodingRangeError[]; THROUGH [0..c-bi) DO h.AppendByte[0]; ENDLOOP; -- store leading 0's h.AppendByte[Inline.BITSHIFT[1,e MOD 8]]; THROUGH [0..bi-1) DO h.AppendByte[0]; ENDLOOP; -- store trailing 0's }; AppendIdentifier: PUBLIC PROCEDURE [h: Handle, id: Rope.ROPE, start: INT _ 0, len: INT _ Rope.MaxLen] = { length: INT _ MIN[len, id.Length[]-start]; j: NAT; h.AppendSequenceDescriptor[sequenceIdentifier, length]; FOR j IN [start..start+length) DO h.AppendByte[LOOPHOLE[Rope.Fetch[id, j], CARDINAL]]; ENDLOOP; }; BytesInInteger: PUBLIC PROCEDURE [n: INT] RETURNS [CARDINAL] = { IF ABS[n] = 0 THEN RETURN[0]; IF ABS[n] > 37777777B AND LOOPHOLE[n, LONG CARDINAL] # 37740000000B THEN RETURN[4]; IF ABS[n] > 77777B AND LOOPHOLE[n, LONG CARDINAL] # 37777700000B THEN RETURN[3]; IF ABS[n] > 127 AND n # -128 THEN RETURN[2]; RETURN[1]; }; WriteInterpressHeader: PUBLIC PROCEDURE [h: Handle] = { --Interpress/Xerox/1.0 -- h.AppendByte[73]; -- I h.AppendByte[110]; -- n h.AppendByte[116]; -- t h.AppendByte[101]; -- e h.AppendByte[114]; -- r h.AppendByte[112]; -- p h.AppendByte[114]; -- r h.AppendByte[101]; -- e h.AppendByte[115]; -- s h.AppendByte[115]; -- s h.AppendByte[47]; -- / h.AppendByte[88]; -- X h.AppendByte[101]; -- e h.AppendByte[114]; -- r h.AppendByte[111]; -- o h.AppendByte[120]; -- x h.AppendByte[47]; -- / h.AppendByte[50]; -- 2 h.AppendByte[46]; -- . h.AppendByte[48]; -- 0 h.AppendByte[32]; -- }; EncodingRangeError: SIGNAL = CODE; Error: PUBLIC ERROR [errorCode: ErrorCode] = CODE; END. <> <> <<>> <> <> <<>> <> <> <<>> <> <> <<>> <> <> <<>> <> <> <<>> <> <> <<>> <> <> <<>>