<<>> <> <> <> <<>> DIRECTORY Basics USING [LongNumber, ShortNumber], BasicTime USING [FromNSTime, GMT, nullGMT, OutOfRange, ToNSTime], CHNameP2V0 USING [], FilingAttributesP10V5 USING [AccessEntrySequence, AccessList, Attribute, AttributeSequence, AttributeSequenceObject, AttributeValue, AttributeValueObject, FileID, Interpretation, InterpretedAttributeType, nullFileID, Ordering, Position, PositionObject, User], FilingP10V5 USING [allDescendants, Control, ControlSequence, ControlSequenceObject, Direction, Filter, FilterObject, FilterType, PatternFilter, RelationFilter, Scope, ScopeObject, ScopeSequence, ScopeSequenceObject, ScopeType, unlimitedCount], RefText USING [InlineAppendChar, ObtainScratch], Rope USING [FromProc, InlineFetch, Length, ROPE], XNSFilingAttributes USING [Interpreted, InterpretedRange]; XNSFilingAttributeImpl: CEDAR MONITOR IMPORTS BasicTime, RefText, Rope EXPORTS XNSFilingAttributes ~ { OPEN FilingP10V5, FilingAttributesP10V5, XNSFilingAttributes; ROPE: TYPE ~ Rope.ROPE; <> InfoFromAttributeSequence: PUBLIC PROC [attributes: AttributeSequence] RETURNS [vers: CARD ¬ 0, bytes: INT ¬ -1, created: BasicTime.GMT ¬ BasicTime.nullGMT, fileType: CARD ¬ 0, pathName: REF TEXT ¬ NIL, fID: FileID ¬ nullFileID, isDir: BOOL ¬ FALSE, numKids: CARD ¬ 0] ~ { FOR i: INT IN [0..attributes.length) DO attribute: Attribute ~ attributes[i]; color: Interpreted; IF ( attribute.type NOT IN InterpretedRange ) THEN LOOP; color ¬ VAL[attribute.type]; SELECT color FROM createdOn => { temp: CARD32 ~ DecapsulateCard32[attribute.value]; created ¬ BasicTime.FromNSTime[temp ! BasicTime.OutOfRange => CONTINUE]; }; numberOfChildren => { numKids ¬ 0; IF ( attribute.value = NIL ) THEN LOOP; IF ( attribute.value.length = 0 ) THEN LOOP; numKids ¬ DecapsulateCard16[attribute.value]; }; dataSize => { bytes ¬ DecapsulateCard32[attribute.value] }; fileID => { fID ¬ DecapsulateFileID[attribute.value] }; isDirectory => { isDir ¬ DecapsulateBoolean[attribute.value] }; pathname => { pathName ¬ DecapsulateRefText[attribute.value] }; type => { fileType ¬ DecapsulateCard32[attribute.value] }; version => { vers ¬ DecapsulateCard16[attribute.value] }; ENDCASE => NULL; ENDLOOP; }; <> nullAttributes: PUBLIC AttributeSequence ¬ NEW[AttributeSequenceObject[0]]; nullControls: PUBLIC ControlSequence ¬ NEW[ControlSequenceObject[0]]; <> BuildScope: PUBLIC PROC [filterType: FilterType, rope: ROPE, type: CARD32] RETURNS [scope: ScopeSequence] = { value: AttributeValue ¬ EncapsulateRope[rope]; filter: Filter; scope ¬ NEW[ScopeSequenceObject[4]]; scope[0] ¬ NEW[ScopeObject.count ¬ [count[unlimitedCount]]]; scope[1] ¬ NEW[ScopeObject.depth ¬ [depth[allDescendants]]]; scope[2] ¬ NEW[ScopeObject.direction ¬ [direction[forward]]]; filter ¬ SELECT filterType FROM matches => NEW [FilterObject.matches ¬ [matches[matches: [attribute: [type: type, value: value]]] ]], equal => NEW [FilterObject.equal ¬ [equal[equal: [attribute: [type: type, value: value], interpretation: string]] ]], ENDCASE => NEW [FilterObject.none ¬ [none[none: [null: 0]] ]]; scope[3] ¬ NEW [ScopeObject.filter ¬ [filter[filter: filter]]]; }; BuildAttribute: PUBLIC PROC [name: ROPE, type: CARD32, time: BasicTime.GMT ¬ BasicTime.nullGMT, timeType: CARD32 ¬ 0] RETURNS [attributes: AttributeSequence] = { IF time = BasicTime.nullGMT THEN { attributes ¬ NEW [AttributeSequenceObject[1]]; attributes[0] ¬ [type: type, value: EncapsulateRope[name]]; RETURN[attributes]; }; attributes ¬ NEW [AttributeSequenceObject[2]]; attributes[0] ¬ [type: timeType, value: EncapsulateCard32[BasicTime.ToNSTime[time]]]; attributes[1] ¬ [type: type, value: EncapsulateRope[name]]; RETURN[attributes]; }; BuildDirectoryAttribute: PUBLIC PROC [nameR: ROPE] RETURNS [attributes: AttributeSequence] = { attributes ¬ NEW [AttributeSequenceObject[3]]; attributes[0] ¬ [type: Interpreted.isDirectory.ORD, value: EncapsulateBoolean[TRUE]]; attributes[1] ¬ [type: Interpreted.name.ORD, value: EncapsulateRope[nameR]]; attributes[2] ¬ [type: Interpreted.type.ORD, value: EncapsulateCard32[1 -- tDirectory --]]; RETURN[attributes]; }; BuildStoreAttributes: PUBLIC PROC [file: ROPE, vers: CARDINAL, created: BasicTime.GMT] RETURNS [attributes: AttributeSequence] ~ { num: CARDINAL ¬ IF ( created = BasicTime.nullGMT ) THEN 2 ELSE 3; attributes ¬ NEW [AttributeSequenceObject[num]]; attributes[0] ¬ [type: Interpreted.name.ORD, value: EncapsulateRope[file]]; attributes[1] ¬ [type: Interpreted.version.ORD, value: EncapsulateCard16[vers]]; IF ( created # BasicTime.nullGMT ) THEN { time: CARD32 ¬ BasicTime.ToNSTime[created]; attributes[2] ¬ [type: Interpreted.createdOn.ORD, value: EncapsulateCard32[time]]; }; }; <> EncapsulateAccessList: PUBLIC PROC [accessList: AccessList] RETURNS [value: AttributeValue] ~ { value ¬ NIL; }; DecapsulateAccessList: PUBLIC PROC [value: AttributeValue] RETURNS [accessList: AccessList] ~ { <> <> <> <> <> <> <> <> <> <<};>> <> <> <> <> <> <> <> <> <<};>> <> <> }; EncapsulateFileID: PUBLIC PROC [fileID: FileID] RETURNS [value: AttributeValue] ~ { len: CARDINAL ~ 5; value ¬ NEW[AttributeValueObject[len]]; FOR i: CARDINAL IN [0..len) DO value[i] ¬ fileID[i]; ENDLOOP; }; DecapsulateFileID: PUBLIC PROC [value: AttributeValue] RETURNS [fileID: FileID] ~ { IF value = NIL THEN ERROR; IF value.length # 5 THEN ERROR; FOR i: CARDINAL IN [0..5) DO fileID[i] ¬ value[i]; ENDLOOP; }; EncapsulateOrdering: PUBLIC PROC [ordering: Ordering] RETURNS [value: AttributeValue] ~ { value ¬ NIL; }; DecapsulateOrdering: PUBLIC PROC [value: AttributeValue] RETURNS [ordering: Ordering] ~ { temp: Basics.LongNumber; IF value = NIL THEN ERROR; IF value.length # 4 THEN ERROR; temp.hi ¬ value[0]; temp.lo ¬ value[1]; ordering.key ¬ temp.lc; ordering.ascending ¬ IF value[2] = 1 THEN TRUE ELSE FALSE; ordering.interpretation ¬ VAL[value[3]]; }; EncapsulatePosition: PUBLIC PROC [position: Position] RETURNS [value: AttributeValue] ~ { value ¬ NIL; }; DecapsulatePosition: PUBLIC PROC [value: AttributeValue] RETURNS [position: Position] ~ { length: CARDINAL; IF value = NIL THEN ERROR; IF value.length <= 0 THEN ERROR; length ¬ value[0]; position ¬ NEW[PositionObject[length]]; FOR i: CARDINAL IN [0..length) DO position.body[i] ¬ value[i+1]; ENDLOOP; }; EncapsulateUser: PUBLIC PROC [name: ROPE] RETURNS [value: AttributeValue] ~ { value ¬ NIL; }; DecapsulateUser: PUBLIC PROC [value: AttributeValue] RETURNS [user: User] ~ { place: NAT ¬ 0; GetRope: PROC [] RETURNS [r: ROPE] = { temp: Basics.ShortNumber; len, i: NAT ¬ 0; P: PROC RETURNS[c: CHAR] = { IF i MOD 2 = 0 THEN {temp.sc ¬ value[place]; place ¬ place + 1; c ¬ VAL[temp.hi]} ELSE {c ¬ VAL[temp.lo]}; i ¬ i + 1; }; len ¬ value[place]; place ¬ place + 1; r ¬ Rope.FromProc[len: len, p: P]; }; IF value = NIL THEN ERROR; user.organization ¬ GetRope[]; user.domain ¬ GetRope[]; user.object ¬ GetRope[]; }; <> EncapsulateBoolean: PUBLIC PROC [b: BOOL] RETURNS [value: AttributeValue] ~ { len: NAT ~ 1; -- wrapped len value ¬ NEW [AttributeValueObject[len]]; value[0] ¬ IF b THEN 1 ELSE 0; }; DecapsulateBoolean: PUBLIC PROC [value: AttributeValue] RETURNS [b: BOOL] ~ { IF value = NIL THEN ERROR; IF value.length # 1 THEN ERROR; b ¬ IF value[0] = 1 THEN TRUE ELSE FALSE; }; EncapsulateCard16: PUBLIC PROC [i: CARD16] RETURNS [value: AttributeValue] ~ { len: NAT ~ 1; -- wrapped len value ¬ NEW [AttributeValueObject[len]]; value[0] ¬ i; }; DecapsulateCard16: PUBLIC PROC [value: AttributeValue] RETURNS [i: CARD16] ~ { IF value = NIL THEN ERROR; IF value.length # 1 THEN ERROR; i ¬ value[0]; }; EncapsulateCard32: PUBLIC PROC [i: CARD32] RETURNS [value: AttributeValue] ~ { temp: Basics.LongNumber; len: NAT ~ 2; -- wrapped len value ¬ NEW [AttributeValueObject[len]]; temp.lc ¬ i; value[0] ¬ temp.hi; value[1] ¬ temp.lo; }; DecapsulateCard32: PUBLIC PROC [value: AttributeValue] RETURNS [i: CARD32] ~ { temp: Basics.LongNumber; IF value = NIL THEN ERROR; IF value.length # 2 THEN ERROR; temp.hi ¬ value[0]; temp.lo ¬ value[1]; i ¬ temp.lc; }; EncapsulateRope: PUBLIC PROC [name: ROPE] RETURNS [value: AttributeValue] ~ { len: NAT ~ (name.Length[]+3) / 2; -- wrapped len value ¬ NEW[AttributeValueObject[len]]; TRUSTED { EncapsulateBytes[@(value.body), name] }; }; DecapsulateRope: PUBLIC PROC [value: AttributeValue] RETURNS [rope: ROPE] ~ { place: NAT ¬ 0; GetRope: PROC [] RETURNS [r: ROPE] = { temp: Basics.ShortNumber; len, i: NAT ¬ 0; P: PROC RETURNS[c: CHAR] = { IF i MOD 2 = 0 THEN {temp.sc ¬ value[place]; place ¬ place + 1; c ¬ VAL[temp.hi]} ELSE {c ¬ VAL[temp.lo]}; i ¬ i + 1; }; len ¬ value[place]; place ¬ place + 1; r ¬ Rope.FromProc[len: len, p: P]; }; IF value = NIL THEN ERROR; rope ¬ GetRope[]; }; DecapsulateRefText: PUBLIC PROC [value: AttributeValue] RETURNS [rope: REF TEXT] ~ { place: NAT ¬ 0; GetRope: PROC [] RETURNS [r: REF TEXT] = { temp: Basics.ShortNumber; len: NAT ¬ 0; P: PROC [i: NAT] RETURNS[c: CHAR] = { IF i MOD 2 = 0 THEN {temp.sc ¬ value[place]; place ¬ place + 1; c ¬ VAL[temp.hi]} ELSE {c ¬ VAL[temp.lo]}; }; len ¬ value[place]; place ¬ place + 1; r ¬ RefText.ObtainScratch[len]; FOR i: NAT IN [0 .. len) DO c: CHAR ~ P[i]; r ¬ RefText.InlineAppendChar[r, c]; ENDLOOP; }; IF value = NIL THEN ERROR; rope ¬ GetRope[]; }; OpaqueByteObject: TYPE ~ MACHINE DEPENDENT RECORD [ length: CARDINAL, <> body: PACKED ARRAY [0..1000) OF CHAR ]; EncapsulateBytes: PUBLIC PROC [bytes: LONG POINTER, rope: ROPE] ~ TRUSTED { len: NAT ~ rope.Length[]; b: LONG POINTER TO OpaqueByteObject ~ bytes; avo: LONG POINTER TO AttributeValueObject ~ bytes; <> avo.body[0] ¬ len; FOR i: NAT IN [0..len) DO b.body[i+2] ¬ rope.InlineFetch[i]; ENDLOOP; IF ( (len MOD 2) = 1 ) THEN b.body[len+2] ¬ 0C; }; EncapsulateNull: PUBLIC PROC RETURNS [value: AttributeValue] ~ { len: NAT ~ 0; -- wrapped len value ¬ NEW [AttributeValueObject[len]]; }; <> << AllInterpretedValues: TYPE ~ REF AllInterpretedValuesRep; AllInterpretedValuesRep: TYPE ~ RECORD [ set: PACKED ARRAY Interpreted OF BOOL, checksum: CARDINAL ]; GetInterpretation: PUBLIC PROC [attribute: Attribute, old: AllInterpretedValues ¬ NIL] RETURNS [new: AllInterpretedValues] ~ { IF old # NIL THEN new ¬ old ELSE { new ¬ NEW[AllInterpretedValuesRep]; new.set ¬ ALL[FALSE] }; IF ( attribute.type IN InterpretedRange ) THEN { color: Interpreted ~ VAL[attribute.type]; new.set[color] ¬ TRUE; SELECT color FROM checksum => { new.checksum ¬ DecapsulateCard16[attribute.value]; }; childrenUniquelyNamed => { new.childrenUniquelyNamed ¬ DecapsulateBoolean[attribute.value] }; createdBy => { new.createdBy ¬ DecapsulateUser[attribute.value] }; createdOn => { new.createdOn ¬ DecapsulateCard32[attribute.value] }; fileID => { new.fileID ¬ DecapsulateFileID[attribute.value] }; isDirectory => { new.isDirectory ¬ DecapsulateBoolean[attribute.value] }; isTemporary => { new.isTemporary ¬ DecapsulateBoolean[attribute.value] }; modifiedBy => { new.modifiedBy ¬ DecapsulateUser[attribute.value] }; modifiedOn => { new.modifiedOn ¬ DecapsulateCard32[attribute.value] }; name => { new.name ¬ DecapsulateRope[attribute.value] }; numberOfChildren => { new.numberOfChildren ¬ DecapsulateCard16[attribute.value] }; ordering => { new.ordering ¬ DecapsulateOrdering[attribute.value] }; parentID => { new.parentID ¬ DecapsulateFileID[attribute.value] }; position => { new.position ¬ DecapsulatePosition[attribute.value] }; readBy => { new.readBy ¬ DecapsulateUser[attribute.value] }; readOn => { new.readOn ¬ DecapsulateCard32[attribute.value] }; dataSize => { new.dataSize ¬ DecapsulateCard32[attribute.value] }; type => { new.type ¬ DecapsulateCard32[attribute.value] }; version => { new.version ¬ DecapsulateCard16[attribute.value] }; accessList => { new.accessList ¬ DecapsulateAccessList[attribute.value] }; defaultAccessList => { new.defaultAccessList ¬ DecapsulateAccessList[attribute.value] }; pathname => { new.pathname ¬ DecapsulateRope[attribute.value] }; storedSize => { new.storedSize ¬ DecapsulateCard32[attribute.value] }; subtreeSize => { new.subtreeSize ¬ DecapsulateCard32[attribute.value] }; subtreeSizeLimit => { new.subtreeSizeLimit ¬ DecapsulateCard32[attribute.value] }; ENDCASE => ERROR; }; }; >> }.