/// <summary>
 /// Update the Offset* fields of the input _SECURITY_DESCRIPTOR structure. 
 /// </summary>
 /// <param name="securityDescriptor">The security descriptor to be updated.</param>
 /// <returns>The encoded byte array.</returns>
 public static void UpdateSecurityDescriptor(ref _SECURITY_DESCRIPTOR sd)
 {
     // Revision (1 byte) + Sbz1 (1 byte) + Control (2 bytes) + OffsetOwner (4 bytes) + OffsetGroup (4 bytes) +
     // OffsetSacl (4 bytes) + OffsetDacl (4 bytes)
     int offset = 20;
     if (sd.OwnerSid != null)
     {
         sd.OffsetOwner = (uint)offset;
         offset += TypeMarshal.GetBlockMemorySize<_SID>(sd.OwnerSid.Value);
     }
     else
     {
         sd.OffsetOwner = 0;
     }
     if (sd.GroupSid != null)
     {
         sd.OffsetGroup = (uint)offset;
         offset += TypeMarshal.GetBlockMemorySize<_SID>(sd.GroupSid.Value);
     }
     else
     {
         sd.OffsetGroup = 0;
     }
     if (sd.Sacl != null)
     {
         sd.OffsetSacl = (uint)offset;
         offset += DtypUtility.EncodeAcl(sd.Sacl.Value).Length;
     }
     else
     {
         sd.OffsetSacl = 0;
     }
     if (sd.Dacl != null)
     {
         sd.OffsetDacl = (uint)offset;
         offset += DtypUtility.EncodeAcl(sd.Dacl.Value).Length;
     }
     else
     {
         sd.OffsetDacl = 0;
     }
 }
        /// <summary>
        /// Access Check Algorithm. MS-DTYP section 2.5.4.1
        /// </summary>
        /// <param name="securityDescriptor">
        /// SECURITY_DESCRIPTOR structure that is assigned to the object.
        /// </param>
        /// <param name="token">
        /// Token is an authorization context containing all SIDs 
        /// that represent the security principal
        /// </param>
        /// <param name="accessRequestMask">
        /// Set of permissions requested on the object.
        /// </param>
        /// <param name="objectTree">
        /// A tree representation of the hierarchy of objects for which 
        /// to check access. Each node represents an object with two values. 
        /// A GUID that represents the object itself and a value called 
        /// Remaining, which indicates the user rights request for that 
        /// node that have not yet been satisfied. It can be null.
        /// </param>
        /// <param name="principalSelfSubstitudeSid">
        /// A SID that logically replaces the SID in any ACE that contains 
        /// the well-known PRINCIPAL_SELF SID. It can be null.
        /// </param>
        /// <returns>
        /// Returns TRUE if access is allowed. Otherwise, it returns FALSE if access is denied. 
        /// </returns>
        /// <exception cref="ArgumentException">
        /// Thrown when the Dacl field of securityDescriptor doesn't exist, but the DACLPresent flag is set.
        /// Thrown when the Revision field of securityDescriptor is invalid
        /// </exception>
        public static bool AccessCheck(
            _SECURITY_DESCRIPTOR securityDescriptor,
            Token token,
            uint accessRequestMask,
            AccessCheckObjectTree objectTree,
            _SID? principalSelfSubstitudeSid)
        {
            //MS-ADTS Section 5.1.3.3.1 Null vs. Empty DACLs
            //The presence of a NULL DACL in the nTSecurityDescriptor attribute of an object grants full
            //access to the object to any principal that requests it; normal access checks are not performed
            //with respect to the object.

            if (securityDescriptor.Revision != 0x1)
            {
                throw new ArgumentException("The Revision field is invalid.", "securityDescriptor");
            }

            if ((securityDescriptor.Control & SECURITY_DESCRIPTOR_Control.DACLPresent)
                == SECURITY_DESCRIPTOR_Control.None)
            {
                return true;
            }
            else if (securityDescriptor.Dacl == null)
            {
                throw new ArgumentException(
                    "The Dacl field of securityDescriptor doesn't exist, but the DACLPresent flag is set.", "securityDescriptor");
            }

            //Pscudocode
            //
            //Set DACL to SecurityDescriptor Dacl field
            //Set RemainingAccess to Access Request mask
            //
            //IF RemainingAccess contains ACCESS_SYSTEM_SECURITY access flag THEN
            //IF Token.Privileges contains SeSecurityPrivilege THEN
            //Remove ACCESS_SYSTEM_SECURITY access bit from RemainingAccess
            //END IF
            //END IF
            //
            //IF RemainingAccess contains WRITE_OWNER access bit THEN
            //IF Token.Privileges contains SeTakeOwnershipPrivilege THEN
            //Remove WRITE_OWNER access bit from RemainingAccess
            //END IF
            //END IF
            //-- the owner of an object is always granted READ_CONTROL and WRITE_DAC.
            //CALL SidInToken( Token, SecurityDescriptor.Owner, PrincipalSelfSubst)
            //IF SidInToken returns True THEN
            //Remove READ_CONTROL and WRITE_DAC from RemainingAccess
            //END IF

            _ACL? dacl = securityDescriptor.Dacl;
            uint remainingAccess = accessRequestMask;
            AccessCheckObjectTree localTree = new AccessCheckObjectTree();
            Guid[] allNodes = new Guid[] { };

            if ((remainingAccess & ACCESS_MASK_ACCESS_SYSTEM_SECURITY) != 0 && token.Privileges != null)
            {
                foreach (_LUID privilege in token.Privileges)
                {
                    if (ObjectUtility.DeepCompare(privilege, GetPrivilegeLuid(PrivilegeName.SE_SECURITY_NAME)))
                    {
                        remainingAccess &= ~ACCESS_MASK_ACCESS_SYSTEM_SECURITY;
                    }
                }
            }
            if ((remainingAccess & ACCESS_MASK_WRITE_OWNER) != 0 && token.Privileges != null)
            {
                foreach (_LUID privilege in token.Privileges)
                {
                    if (ObjectUtility.DeepCompare(privilege, GetPrivilegeLuid(PrivilegeName.SE_TAKE_OWNERSHIP_NAME)))
                    {
                        remainingAccess &= ~ACCESS_MASK_WRITE_OWNER;
                    }
                }
            }
            if (securityDescriptor.OwnerSid != null
                && SidInToken(token, securityDescriptor.OwnerSid.Value, principalSelfSubstitudeSid))
            {
                remainingAccess &= ~(uint)(ACCESS_MASK_READ_CONTROL | ACCESS_MASK_WRITE_DAC);
            }

            //IF Object Tree is not NULL THEN
            //Set LocalTree to Object Tree
            //FOR each node in LocalTree DO
            //Set node.Remaining to RemainingAccess
            //END FOR
            //END IF

            if (objectTree != null && objectTree.Root != null)
            {
                localTree = (AccessCheckObjectTree)ObjectUtility.DeepClone(objectTree);
                List<Guid> tmpList = new List<Guid>();
                tmpList.Add(localTree.Root.Value);
                tmpList.AddRange(localTree.GetDescendentNodes(localTree.Root.Value));
                allNodes = tmpList.ToArray();
                foreach (Guid node in allNodes)
                {
                    localTree.SetTreeNodeData(node, remainingAccess);
                }
            }

            //FOR each ACE in DACL DO
            //IF ACE.flag does not contain INHERIT_ONLY_ACE THEN
            //CASE ACE.Type OF
            //CASE Allow Access:
            //CALL SidInToken( Token, ACE.Sid, and PrincipalSelfSubst )
            //IF SidInToken returns True THEN
            //    Remove ACE.AccessMask from RemainingAccess
            //    FOR each node in LocalTree DO
            //    Remove ACE.AccessMask from node.Remaining
            //END FOR
            //END IF
            //CASE Deny Access:
            //CALL SidInToken( Token, ACE.Sid, PrincipalSelfSubst )
            //IF SidInToken returns True THEN
            //    IF any bit of RemainingAccess is in ACE.AccessMask THEN
            //    Return access_denied
            //END IF
            //END IF
            //CASE Object Allow Access:
            //CALL SidInToken( Token, ACE.Sid, PrincipalSelfSubst )
            //IF SidInToken returns True THEN
            //    IF ACE.Object is contained in LocalTree THEN
            //    Locate node n in LocalTree such that
            //    n.GUID is the same as ACE.Object
            //    Remove ACE.AccessMask from n.Remaining
            //    FOR each node ns such that ns is a descendent of n DO
            //    Remove ACE.AccessMask from ns.Remaining
            //    END FOR
            //    FOR each node np such that np is an ancestor of n DO
            //    Set np.Remaining = np.Remaining or np-1.Remaining
            //END FOR
            //END IF
            //END IF
            //CASE Object Deny Access:
            //CALL SidInToken( Token, ACE.Sid, PrincipalSelfSubst )
            //IF SidInToken returns True THEN
            //    Locate node n in LocalTree such that
            //    n.GUID is the same as ACE.Object
            //    IF n exists THEN
            //    If any bit of n.Remaining is in ACE.AccessMask THEN
            //    Return access_denied
            //END IF
            //END IF
            //END IF
            //END CASE
            //END IF
            //END FOR

            if (dacl.Value.Aces != null)
            {
                foreach (object ace in dacl.Value.Aces)
                {
                    _ACE_HEADER header = (_ACE_HEADER)ObjectUtility.GetFieldValue(ace, "Header");
                    _SID sid = (_SID)ObjectUtility.GetFieldValue(ace, "Sid");

                    if ((header.AceFlags & ACE_FLAGS.INHERIT_ONLY_ACE) == ACE_FLAGS.INHERIT_ONLY_ACE
                        || !SidInToken(token, sid, principalSelfSubstitudeSid))
                    {
                        continue;
                    }

                    bool ret = DtypUtility.AceAccessCheck(ace, ref remainingAccess, ref localTree, allNodes);
                    if (ret == false)
                    {
                        return false;
                    }
                }
            }

            //IF RemainingAccess = 0 THEN
            //Return success
            //Else
            //Return access_denied
            //END IF

            bool status;
            if (objectTree != null && objectTree.Root != null)
            {
                status = (localTree.GetTreeNodeData(localTree.Root.Value) == 0);
            }
            else
            {
                status = (remainingAccess == 0);
            }
            return status;
        }
        /// <summary>
        /// Convert _SECURITY_DESCRIPTOR to SDDL string.
        /// </summary>
        /// <param name="securityDescriptor">_SECURITY_DESCRIPTOR to convert.</param>
        /// <returns>SDDL string.</returns>
        public static string ToSddlString(_SECURITY_DESCRIPTOR securityDescriptor)
        {
            byte[] securityDescriptorBytes = DtypUtility.EncodeSecurityDescriptor(securityDescriptor);
            RawSecurityDescriptor rawSecurityDescriptor = new RawSecurityDescriptor(securityDescriptorBytes, 0);

            return rawSecurityDescriptor.GetSddlForm(AccessControlSections.All);
        }
        /// <summary>
        /// MandatoryIntegrityCheck. MS-DTYP section 2.5.4.1
        /// </summary>
        /// <param name="tokenIntegritySID">
        /// Mandatory Integrity SID in the Token
        /// </param>
        /// <param name="aceIntegritySID">
        /// Mandatory Integrity label SID in the Security descriptor of the object
        /// </param>
        /// <param name="mandatoryInformation">
        /// Output of the function describing the allowable bits for the caller
        /// </param>
        /// <param name="token">
        /// Authorization context
        /// </param>
        /// <param name="objectSecurityDescriptor">
        /// SECURITY_DESCRIPTOR structure that is assigned to the object
        /// </param>
        /// <returns>True if check is done successfully; otherwise, false</returns>
        public static bool MandatoryIntegrityCheck(
            _SID tokenIntegritySID,
            _SID aceIntegritySID,
            out uint mandatoryInformation,
            Token token,
            _SECURITY_DESCRIPTOR objectSecurityDescriptor)
        {
            //Set TokenPolicy to Token MandatoryPolicy field
            //Set ObjectIntegrityACE to SecurityDescriptor ObjectIntegrity ACE field
            //Set ObjectIntegrityAceMask to SecurityDescriptor ObjectIntegrity Accessmask field
            //
            //IF TokenPolicy.Policy EQUAL TOKEN_MANDATORY_POLICY_OFF OR
            //TokenPolicy.Policy EQUAL TOKEN_MANDATORY_POLICY_NEW_PROCESS_MIN THEN
            //Set MandatoryInformation.AllowedAccess to GENERIC_ALL
            //Return success
            //END IF
            //
            //IF ObjectIntegrityACE.AceFlag NOT EQUAL INHERIT_ONLY_ACE THEN
            //Set AceMask to ObjectIintegrityACE.AccessMask
            //Set AceIntegritysid to ObjectIntegrityACE.TrusteeSid
            //ELSE
            //Set AceMask to SYSTEM_MANDATORY_LABEL_NO_WRITE_UP
            //--The DefaultMandatorySid is derived from policy managed in an
            //--implementation specific manner. The SID for ML_MEDIUM is used by
            //--Windows.
            //Set AceIntegritysid to DefaultMandatorySid
            //END IF

            TokenMandatoryPolicyValue tokenPolicy = token.MandatoryPolicy;
            _SYSTEM_MANDATORY_LABEL_ACE? objectIntegrityACE = null;
            mandatoryInformation = 0;
            bool tokenDominates;

            if (tokenPolicy == TokenMandatoryPolicyValue.TOKEN_MANDATORY_POLICY_OFF
                || tokenPolicy == TokenMandatoryPolicyValue.TOKEN_MANDATORY_POLICY_NEW_PROCESS_MIN)
            {
                mandatoryInformation = ACCESS_MASK_GENERIC_ALL;
                return true;
            }

            if ((objectSecurityDescriptor.Control & SECURITY_DESCRIPTOR_Control.SACLPresent)
                    == SECURITY_DESCRIPTOR_Control.SACLPresent
                && objectSecurityDescriptor.Sacl != null)
            {
                if (objectSecurityDescriptor.Sacl.Value.Aces != null)
                {
                    foreach (object ace in objectSecurityDescriptor.Sacl.Value.Aces)
                    {
                        _SID sid = (_SID)ObjectUtility.GetFieldValue(ace, "Sid");
                        if (ObjectUtility.DeepCompare(sid, aceIntegritySID))
                        {
                            objectIntegrityACE = (_SYSTEM_MANDATORY_LABEL_ACE)ace;
                        }
                    }
                }
            }

            SYSTEM_MANDATORY_LABEL_ACE_Mask objectIntegrityAceMask;
            _SID aceIntegritySid;

            if (objectIntegrityACE != null && objectIntegrityACE.Value.Header.AceFlags != ACE_FLAGS.INHERIT_ONLY_ACE)
            {
                objectIntegrityAceMask = objectIntegrityACE.Value.Mask;
                aceIntegritySid = objectIntegrityACE.Value.Sid;
            }
            else
            {
                objectIntegrityAceMask = SYSTEM_MANDATORY_LABEL_ACE_Mask.SYSTEM_MANDATORY_LABEL_NO_WRITE_UP;
                //The DefaultMandatorySid is derived from policy managed in an
                //implementation specific manner. The SID for ML_MEDIUM is used by
                //Windows.
                aceIntegritySid = GetWellKnownSid(WellKnownSid.ML_MEDIUM, null);
            }
            //
            //Note:SidDominates is removed from the current function, because it's declared but not used.
            //
            //CALL sidEqual(AceIntegritysid, TokenIntegritysid)
            //IF AceIntegritySid EQUALS Token.MandatoryIntegritySid THEN
            //Set TokenDominates to TRUE
            //Set ObjectDominates to TRUE
            //ELSE
            //CALL SidDominates (Token.MandatoryIntegritySid, AceIntegritysid)
            //IF SidDominates returns TRUE THEN
            //Set TokenDominates to TRUE
            //ELSE
            //Set TokenDominates to FALSE
            //END IF
            //Set ObjectDominates to NOT(TokenDominates)
            //END IF

            tokenDominates = SidDominates((_SID)token.IntegrityLevelSid, aceIntegritySid);

            //IF TokenPolicy EQUAL TOKEN_MANDATORY_POLICY_NO_WRITE_UP THEN
            //Add READ to MandatoryInformation.AllowedAccess
            //Add EXECUTE to MandatoryInformation.AllowedAccess
            //IF TokenDominates is TRUE THEN
            //Add WRITE to MandatoryInformation.AllowedAccess
            //END IF
            //END IF
            //
            //IF TokenDominates is FALSE THEN
            //IF ObjectIntegrityAceMask & SYSTEM_MANDATORY_LABEL_NO_READ_UP THEN
            //Remove READ from MandatoryInformation.AllowedAccess
            //END IF
            //IF ObjectIntegrityAceMask & SYSTEM_MANDATORY_LABEL_NO_WRITE_UP THEN
            //Remove WRITE from MandatoryInformation.AllowedAccess
            //END IF
            //IF ObjectIntegrityAceMask & SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP THEN
            //Remove EXECUTE from MandatoryInformation.AllowedAccess
            //END IF
            //END IF
            //
            //IF Token.Privileges contains SeRelabelPrivilegeTHEN
            //Add WRITE_OWNER to MandatoryInformation.AllowedAccess
            //END IF

            if (tokenPolicy == TokenMandatoryPolicyValue.TOKEN_MANDATORY_POLICY_NO_WRITE_UP)
            {
                mandatoryInformation |= ACCESS_MASK_GENERIC_READ;
                mandatoryInformation |= ACCESS_MASK_GENERIC_EXECUTE;
                if (tokenDominates)
                {
                    mandatoryInformation |= ACCESS_MASK_GENERIC_WRITE;
                }
            }

            if (!tokenDominates)
            {
                if ((objectIntegrityAceMask
                    & SYSTEM_MANDATORY_LABEL_ACE_Mask.SYSTEM_MANDATORY_LABEL_NO_READ_UP)
                    == SYSTEM_MANDATORY_LABEL_ACE_Mask.SYSTEM_MANDATORY_LABEL_NO_READ_UP)
                {
                    mandatoryInformation &= ~ACCESS_MASK_GENERIC_READ;
                }
                if ((objectIntegrityAceMask
                    & SYSTEM_MANDATORY_LABEL_ACE_Mask.SYSTEM_MANDATORY_LABEL_NO_WRITE_UP)
                    == SYSTEM_MANDATORY_LABEL_ACE_Mask.SYSTEM_MANDATORY_LABEL_NO_WRITE_UP)
                {
                    mandatoryInformation &= ~ACCESS_MASK_GENERIC_WRITE;
                }
                if ((objectIntegrityAceMask
                    & SYSTEM_MANDATORY_LABEL_ACE_Mask.SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP)
                    == SYSTEM_MANDATORY_LABEL_ACE_Mask.SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP)
                {
                    mandatoryInformation &= ~ACCESS_MASK_GENERIC_EXECUTE;
                }
            }

            if (token.Privileges != null)
            {
                foreach (_LUID privilege in token.Privileges)
                {
                    if (ObjectUtility.DeepCompare(privilege, GetPrivilegeLuid(PrivilegeName.SE_RELABEL_NAME)))
                    {
                        mandatoryInformation |= ACCESS_MASK_WRITE_OWNER;
                    }
                }
            }
            return true;
        }
        /// <summary>
        /// Encode the _SECURITY_DESCRIPTOR structure into byte array, according to TD specification.
        /// </summary>
        /// <param name="securityDescriptor">The security descriptor to be retrieved.</param>
        /// <returns>The encoded byte array.</returns>
        public static byte[] EncodeSecurityDescriptor(_SECURITY_DESCRIPTOR securityDescriptor)
        {
            if ((securityDescriptor.Control & SECURITY_DESCRIPTOR_Control.SelfRelative) == 0)
            {
                securityDescriptor = DtypUtility.CreateSecurityDescriptor(
                    securityDescriptor.Control,
                    securityDescriptor.OwnerSid,
                    securityDescriptor.GroupSid,
                    securityDescriptor.Sacl,
                    securityDescriptor.Dacl);
            }

            List<byte> byteArray = new List<byte>();
            byteArray.Add(securityDescriptor.Revision);
            byteArray.Add(securityDescriptor.Sbz1);
            byteArray.AddRange(TypeMarshal.ToBytes<SECURITY_DESCRIPTOR_Control>(securityDescriptor.Control));
            byteArray.AddRange(TypeMarshal.ToBytes<uint>(securityDescriptor.OffsetOwner));
            byteArray.AddRange(TypeMarshal.ToBytes<uint>(securityDescriptor.OffsetGroup));
            byteArray.AddRange(TypeMarshal.ToBytes<uint>(securityDescriptor.OffsetSacl));
            byteArray.AddRange(TypeMarshal.ToBytes<uint>(securityDescriptor.OffsetDacl));
            if (securityDescriptor.OwnerSid != null)
            {
                byteArray.AddRange(TypeMarshal.ToBytes<_SID>(securityDescriptor.OwnerSid.Value));
            }
            if (securityDescriptor.GroupSid != null)
            {
                byteArray.AddRange(TypeMarshal.ToBytes<_SID>(securityDescriptor.GroupSid.Value));
            }
            if (securityDescriptor.Sacl != null)
            {
                byteArray.AddRange(DtypUtility.EncodeAcl(securityDescriptor.Sacl.Value));
            }
            if (securityDescriptor.Dacl != null)
            {
                byteArray.AddRange(DtypUtility.EncodeAcl(securityDescriptor.Dacl.Value));
            }
            return byteArray.ToArray();
        }
        /// <summary>
        /// Decode the specified buffer into the _SECURITY_DESCRIPTOR structure.
        /// </summary>
        /// <param name="buffer">The byte array to be decoded.</param>
        /// <returns>The _SECURITY_DESCRIPTOR structure.</returns>
        public static _SECURITY_DESCRIPTOR DecodeSecurityDescriptor(byte[] buffer)
        {
            int offset = 0;

            _SECURITY_DESCRIPTOR securityDescriptor = new _SECURITY_DESCRIPTOR();
            securityDescriptor.Revision = buffer[offset];
            offset += sizeof(byte);
            securityDescriptor.Sbz1 = buffer[offset];
            offset += sizeof(byte);
            securityDescriptor.Control = TypeMarshal.ToStruct<SECURITY_DESCRIPTOR_Control>(
                ArrayUtility.SubArray(buffer, offset, sizeof(SECURITY_DESCRIPTOR_Control)));
            offset += sizeof(ushort);
            securityDescriptor.OffsetOwner = TypeMarshal.ToStruct<uint>(
                ArrayUtility.SubArray(buffer, offset, sizeof(uint)));
            offset += sizeof(uint);
            securityDescriptor.OffsetGroup = TypeMarshal.ToStruct<uint>(
                ArrayUtility.SubArray(buffer, offset, sizeof(uint)));
            offset += sizeof(uint);
            securityDescriptor.OffsetSacl = TypeMarshal.ToStruct<uint>(
                ArrayUtility.SubArray(buffer, offset, sizeof(uint)));
            offset += sizeof(uint);
            securityDescriptor.OffsetDacl = TypeMarshal.ToStruct<uint>(
                ArrayUtility.SubArray(buffer, offset, sizeof(uint)));
            offset += sizeof(uint);

            if (securityDescriptor.OffsetOwner != 0)
            {
                byte subAuthorityCount = buffer[securityDescriptor.OffsetOwner + sizeof(byte)];
                //Size of Revision,SubAuthorityCount, IdentifierAuthority and SubAuthority.
                int sizeOfSid = sizeof(byte) + sizeof(byte) + sizeof(byte) * 6 + sizeof(uint) * subAuthorityCount;
                securityDescriptor.OwnerSid = TypeMarshal.ToStruct<_SID>(
                    ArrayUtility.SubArray(buffer, (int)securityDescriptor.OffsetOwner, sizeOfSid));
            }
            if (securityDescriptor.OffsetGroup != 0)
            {
                byte subAuthorityCount = buffer[securityDescriptor.OffsetGroup + sizeof(byte)];
                //Size of Revision,SubAuthorityCount, IdentifierAuthority and SubAuthority.
                int sizeOfSid = sizeof(byte) + sizeof(byte) + sizeof(byte) * 6 + sizeof(uint) * subAuthorityCount;
                securityDescriptor.GroupSid = TypeMarshal.ToStruct<_SID>(
                    ArrayUtility.SubArray(buffer, (int)securityDescriptor.OffsetGroup, sizeOfSid));
            }
            if (securityDescriptor.OffsetSacl != 0)
            {
                //Add offset of AclRevision and Sbz1.
                ushort aclSize = TypeMarshal.ToStruct<ushort>(
                    ArrayUtility.SubArray(buffer, (int)(securityDescriptor.OffsetSacl + sizeof(byte) + sizeof(byte)), sizeof(ushort)));
                securityDescriptor.Sacl = DtypUtility.DecodeAcl(
                    ArrayUtility.SubArray(buffer, (int)securityDescriptor.OffsetSacl, aclSize));
            }
            if (securityDescriptor.OffsetDacl != 0)
            {
                //Add offset of AclRevision and Sbz1.
                ushort aclSize = TypeMarshal.ToStruct<ushort>(
                    ArrayUtility.SubArray(buffer, (int)(securityDescriptor.OffsetDacl + sizeof(byte) + sizeof(byte)), sizeof(ushort)));
                securityDescriptor.Dacl = DtypUtility.DecodeAcl(
                    ArrayUtility.SubArray(buffer, (int)securityDescriptor.OffsetDacl, aclSize));
            }

            return securityDescriptor;
        }
        /// <summary>
        /// Create SecurityDescriptor in absolute format. MS-DTYP section 2.5.4.3
        /// </summary>
        /// <param name="parentDescriptor">
        /// Security descriptor for the parent (container) object of the new object. 
        /// If the object has no parent, this parameter is null.
        /// </param>
        /// <param name="creatorDescriptor">
        /// Security descriptor for the new object provided by the creator of the object. 
        /// Caller can pass null.
        /// </param>
        /// <param name="isContainerObject">
        /// TRUE when the object is a container; otherwise, FALSE.
        /// </param>
        /// <param name="objectTypes">
        /// An array of pointers to GUID structures that identify the object types or 
        /// classes of the object associated with NewDescriptor (the return value). 
        /// For Active Directory objects, this array contains pointers to the class 
        /// GUIDs of the object's structural class and all attached auxiliary classes. 
        /// If the object for which this descriptor is being created does not have a GUID, 
        /// this field MUST be set to null.
        /// </param>
        /// <param name="autoInheritFlags">
        /// A set of bit flags that control how access control entries (ACEs) are 
        /// inherited from ParentDescriptor.
        /// </param>
        /// <param name="token">
        /// Token supplied by the caller for default security information for the new object.
        /// </param>
        /// <param name="genericMapping">
        /// Mapping of generic permissions to resource manager-specific permissions 
        /// supplied by the caller.
        /// </param>
        /// <returns>
        /// Output security descriptor for the object computed by the algorithm.
        /// </returns>
        /// <exception cref="ArgumentException">
        /// Thrown when the OwnerSid or GroupSid field of parentDescriptor is null, but
        /// autoInheritFlags is set to DEFAULT_OWNER_FROM_PARENT or DEFAULT_GROUP_FROM_PARENT.
        /// Thrown when the Dacl field of parentDescriptor doesn't exist, but the DACLPresent flag is set.
        /// Thrown when the Sacl field of parentDescriptor doesn't exist, but the SP flag is set.
        /// </exception>
        public static _SECURITY_DESCRIPTOR CreateSecurityDescriptor(
            _SECURITY_DESCRIPTOR? parentDescriptor,
            _SECURITY_DESCRIPTOR? creatorDescriptor,
            bool isContainerObject,
            Guid[] objectTypes,
            SecurityDescriptorAutoInheritFlags autoInheritFlags,
            Token token,
            GenericMapping genericMapping)
        {
            const byte DEFAULT_REVISION = 1;

            _SECURITY_DESCRIPTOR newDescriptor = new _SECURITY_DESCRIPTOR();
            newDescriptor.Revision = DEFAULT_REVISION;

            //Compute the Owner field (v20100908)

            //IF CreatorDescriptor.Owner is NULL THEN
            //IF AutoInheritFlags contains DEFAULT_OWNER_FROM_PARENT THEN
            //Set NewDescriptor.Owner to ParentDescriptor.Owner
            //ELSE
            //Set NewDescriptor.Owner to Token.SIDs[Token.OwnerIndex]
            //ENDIF
            //ELSE
            //Set NewDescriptor.Owner to CreatorDescriptor.Owner
            //ENDIF

            if (creatorDescriptor != null)
            {
                newDescriptor.OwnerSid = creatorDescriptor.Value.OwnerSid;
            }
            else if ((autoInheritFlags & SecurityDescriptorAutoInheritFlags.DEFAULT_OWNER_FROM_PARENT)
                == SecurityDescriptorAutoInheritFlags.DEFAULT_OWNER_FROM_PARENT)
            {
                if (parentDescriptor != null)
                {
                    newDescriptor.OwnerSid = parentDescriptor.Value.OwnerSid;
                }
                else
                {
                    throw new ArgumentException(
                        "The parentDescriptor doesn't exist, but DEFAULT_OWNER_FROM_PARENT flag is set.",
                        "parentDescriptor");
                }
            }
            else
            {
                newDescriptor.OwnerSid = token.Sids[token.OwnerIndex];
            }

            //Compute the Group field

            //IF CreatorDescriptor.Group is NULL THEN
            //IF AutoInheritFlags contains DEFAULT_GROUP_FROM_PARENT THEN
            //Set NewDescriptor.Group to ParentDescriptor.Group
            //ELSE
            //Set NewDescriptor.Group to Token.SIDs[Token.PrimaryGroup]
            //ENDIF
            //ELSE
            //Set NewDescriptor.Group to CreatorDescriptor.Group
            //ENDIF
            if (creatorDescriptor != null)
            {
                newDescriptor.GroupSid = creatorDescriptor.Value.GroupSid;
            }
            else if ((autoInheritFlags & SecurityDescriptorAutoInheritFlags.DEFAULT_GROUP_FROM_PARENT)
                == SecurityDescriptorAutoInheritFlags.DEFAULT_GROUP_FROM_PARENT)
            {
                if (parentDescriptor != null)
                {
                    newDescriptor.GroupSid = parentDescriptor.Value.GroupSid;
                }
                else
                {
                    throw new ArgumentException(
                        "The parentDescriptor doesn't exist, but DEFAULT_GROUP_FROM_PARENT flag is set.",
                        "parentDescriptor");
                }
            }
            else
            {
                newDescriptor.GroupSid = token.Sids[token.PrimaryGroup];
            }

            _ACL? parentDacl = null;
            _ACL? parentSacl = null;
            SECURITY_DESCRIPTOR_Control parentControl = SECURITY_DESCRIPTOR_Control.None;
            _ACL? creatorDacl = null;
            _ACL? creatorSacl = null;
            SECURITY_DESCRIPTOR_Control creatorControl = SECURITY_DESCRIPTOR_Control.None;
            #region Check Sacl or Dacl filed against SP or DACLPresent flag in the control field.

            if (parentDescriptor != null)
            {
                parentControl = parentDescriptor.Value.Control;
                if ((parentDescriptor.Value.Control & SECURITY_DESCRIPTOR_Control.DACLPresent)
                         == SECURITY_DESCRIPTOR_Control.DACLPresent)
                {
                    if (parentDescriptor.Value.Dacl == null)
                    {
                        throw new ArgumentException(
                            "The Dacl field of parentDescriptor doesn't exist, but the DACLPresent flag is set.",
                            "parentDescriptor");
                    }
                    else
                    {
                        parentDacl = parentDescriptor.Value.Dacl;
                    }
                }
                if ((parentDescriptor.Value.Control & SECURITY_DESCRIPTOR_Control.SACLPresent)
                        == SECURITY_DESCRIPTOR_Control.SACLPresent)
                {
                    if (parentDescriptor.Value.Sacl == null)
                    {
                        throw new ArgumentException(
                            "The Sacl field of parentDescriptor doesn't exist, but the SP flag is set.",
                            "parentDescriptor");
                    }
                    else
                    {
                        parentSacl = parentDescriptor.Value.Sacl;
                    }
                }
            }
            if (creatorDescriptor != null)
            {
                creatorControl = creatorDescriptor.Value.Control;
                if ((creatorDescriptor.Value.Control & SECURITY_DESCRIPTOR_Control.DACLPresent)
                        == SECURITY_DESCRIPTOR_Control.DACLPresent)
                {
                    if (creatorDescriptor.Value.Dacl == null)
                    {
                        throw new ArgumentException(
                            "The Dacl field of creatorDescriptor doesn't exist, but the DACLPresent flag is set.",
                            "creatorDescriptor");
                    }
                    else
                    {
                        creatorDacl = creatorDescriptor.Value.Dacl;
                    }
                }
                if ((creatorDescriptor.Value.Control & SECURITY_DESCRIPTOR_Control.SACLPresent)
                        == SECURITY_DESCRIPTOR_Control.SACLPresent)
                {
                    if (creatorDescriptor.Value.Sacl == null)
                    {
                        throw new ArgumentException(
                            "The Sacl field of creatorDescriptor doesn't exist, but the SP flag is set.",
                            "creatorDescriptor");
                    }
                    else
                    {
                        creatorSacl = creatorDescriptor.Value.Sacl;
                    }
                }
            }

            #endregion

            //Compute the DACL

            //CALL ComputeACL WITH
            //COMPUTE_DACL, ParentDescriptor.DACL, ParentDescriptor.Control,
            //CreatorDescriptor.DACL,CreatorDescriptor.Control
            //IsContainerObject, ObjectTypes, GenericMapping,
            //NewDescriptor.Owner, NewDescriptor.Group, Token
            //RETURNING NewDACL, NewControl
            //Set NewDescriptor.DACL to NewDACL
            //Set NewDescriptor.Control to NewControl

            SECURITY_DESCRIPTOR_Control newControl = SECURITY_DESCRIPTOR_Control.None;
            _ACL? newDacl = ComputeACL(
               AclComputeType.COMPUTE_DACL,
               parentDacl,
               parentControl,
               creatorDacl,
               creatorControl,
               isContainerObject,
               objectTypes,
               autoInheritFlags,
               genericMapping,
               newDescriptor.OwnerSid.Value,
               newDescriptor.GroupSid.Value,
               token,
               out newControl);

            newDescriptor.Dacl = newDacl;
            newDescriptor.Control = newControl;

            //Compute the SACL

            //CALL ComputeACL WITH
            //COMPUTE_SACL, ParentDescriptor.SACL, ParentDescriptor.Control,
            //CreatorDescriptor.SACL,CreatorDescriptor.Control
            //IsContainerObject, ObjectTypes, GenericMapping,
            //NewDescriptor.Owner, NewDescriptor.Group, Token
            //RETURNING NewSACL, NewControl
            //Set NewDescriptor.SACLto NewSACL
            //Set NewDescriptor.Control to (NewDescriptor.Control OR NewControl)
            //RETURN NewDescriptor

            _ACL? newSacl = ComputeACL(
                    AclComputeType.COMPUTE_SACL,
                    parentSacl,
                    parentControl,
                    creatorSacl,
                    creatorControl,
                    isContainerObject,
                    objectTypes,
                    autoInheritFlags,
                    genericMapping,
                    newDescriptor.OwnerSid.Value,
                    newDescriptor.GroupSid.Value,
                    token,
                    out newControl);

            newDescriptor.Sacl = newSacl;
            newDescriptor.Control |= newControl;

            //New SecurityDescriptor is in absolute format.
            newDescriptor.Control = newDescriptor.Control & (~SECURITY_DESCRIPTOR_Control.SelfRelative);
            return newDescriptor;
        }