#if !defined(_FUSION_ID_IDP_H_INCLUDED_)
#define _FUSION_ID_IDP_H_INCLUDED_

/*++

Copyright (c) 1989  Microsoft Corporation

Module Name:

    idp.h

Abstract:

    private definitions for assembly identity

Author:

    Michael Grier (MGrier) 7/27/2000

Revision History:

--*/

#pragma once

#include "debmacro.h"
#include "fusiontrace.h"
#include "fusionhashstring.h"
#include "fusionheap.h"
#include "util.h"

#include <sxstypes.h>
#include <sxsapi.h>

//
//  Power of two to which to round the number of allocated attribute
//  pointers.
//

#define ROUNDING_FACTOR_BITS (3)

#define WILDCARD_CHAR '*'

//
//  Note! Do not change this algorithm lightly.  Encoded identities stored in the
//  filesystem contain hashes using it.  Actually, just do not change it.
//

#define HASH_ALGORITHM HASH_STRING_ALGORITHM_X65599

typedef struct _ASSEMBLY_IDENTITY_NAMESPACE {
    ULONG Hash;
    DWORD Flags;
    SIZE_T NamespaceCch;
    const WCHAR *Namespace;
} ASSEMBLY_IDENTITY_NAMESPACE, *PASSEMBLY_IDENTITY_NAMESPACE;

typedef const ASSEMBLY_IDENTITY_NAMESPACE *PCASSEMBLY_IDENTITY_NAMESPACE;

//
//  Internal-use ASSEMBLY_IDENTITY_ATTRIBUTE struct that
//  also contains the hash of the attribute definition.
//

typedef struct _INTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE {
    // NOTE!!! It is very important that the Attribute member appear first in this struct;
    // there are several places in the code that make this assumption.  If it is not true,
    // the code will break!
    // Note also that the Attribute's namespace string is actually allocated in common
    // for all attributes with the same namespace.
    ASSEMBLY_IDENTITY_ATTRIBUTE Attribute;
    PCASSEMBLY_IDENTITY_NAMESPACE Namespace;
    ULONG NamespaceAndNameHash;
    ULONG WholeAttributeHash;
} INTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE, *PINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE;

C_ASSERT(FIELD_OFFSET(INTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE, Attribute) == 0);

typedef const INTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE *PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE;

#define ASSEMBLY_IDENTITY_INTERNAL_FLAG_ATTRIBUTE_POINTERS_IN_SEPARATE_ALLOCATION   (0x00000001)
#define ASSEMBLY_IDENTITY_INTERNAL_FLAG_SINGLE_ALLOCATION_FOR_EVERYTHING            (0x00000002)
#define ASSEMBLY_IDENTITY_INTERNAL_FLAG_NAMESPACE_POINTERS_IN_SEPARATE_ALLOCATION   (0x00000004)

//
//  Revelation of the ASSEMBLY_IDENTITY struct:
//

typedef struct _ASSEMBLY_IDENTITY {
    DWORD Flags;
    ULONG InternalFlags;
    ULONG Type;
    ULONG Hash;
    ULONG AttributeCount;
    ULONG AttributeArraySize; // preallocated a little larger so that we don't have to keep growing
    ULONG NamespaceCount;
    ULONG NamespaceArraySize;
    BOOL  HashDirty;
    PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE *AttributePointerArray;
    PCASSEMBLY_IDENTITY_NAMESPACE *NamespacePointerArray;
} ASSEMBLY_IDENTITY;

//
//  Header for encoded/serialized assembly identities:
//

#define ENCODED_ASSEMBLY_IDENTITY_HEADER_MAGIC ((ULONG) 'dIAE')

//
//  Encoded assembly identity layout:
//
//      ENCODED_ASSEMBLY_IDENTITY_HEADER
//      <AttributeCount hashes of the attributes, sorted by the hash value>
//      <NamespaceCount ENCODED_ASSEMBLY_IDENTITY_NAMESPACE_HEADER headers, each
//          followed by the unicode namespace value>
//      <AttributeCount ENCODED_ASSEMBLY_IDENTITY_ATTRIBUTE_HEADER headers, each
//          followed by the unicode attribute name and value>
//
//
//      e.g.
//
//      <begin ENCODED_ASSEMBLY_IDENTITY_HEADER>
//      00000000:   00000038            HeaderSize == sizeof(ENCODED_ASSEMBLY_IDENTITY_HEADER)
//      00000004:   'EAId'              Magic (ENCODED_ASSEMBLY_IDENTITY_HEADER_MAGIC)
//      00000008:   0000014C            TotalSize
//      0000000C:   00000000            Flags
//      00000010:   00000001            Type (1 = ASSEMBLY_IDENTITY_TYPE_DEFINITION)
//      00000014:   00000000            EncodingFlags
//      00000018:   00000001            HashAlgorithm (1 = HASH_STRING_ALGORITHM_X65599)
//      0000001C:   ????????            Logical hash value of entire identity based on hash algorithm
//                                      (algorithm described in more detail below...)
//      00000020:   00000003            AttributeCount
//      00000024:   00000002            NamespaceCount
//      00000028:   00000000            ReservedMustBeZero1
//      0000002C:   00000000            ReservedMustBeZero2
//      00000030:   00000000 00000000   ReservedMustBeZero3
//      00000038:   00000000 00000000   ReservedMustBeZero4
//      <end ENCODED_ASSEMBLY_IDENTITY_HEADER>
//      <begin sorted attribute hash list>
//      00000040:   xxxxxxxx            hash of attribute #1
//      00000044:   yyyyyyyy            hash of attribute #0 - note that yyyyyyyy >= xxxxxxxx
//      00000048:   zzzzzzzz            hash of attribute #2 - note that zzzzzzzz >= yyyyyyyy
//      <end sorted attribute hash list>
//      <begin namespace length list>
//      0000004C:   00000015            length (in Unicode chars) of namespace #1 - "http://www.amazon.com" - 21 chars = 0x00000015
//      00000050:   00000018            length (in Unicode chars) of namespace #2 - "http://www.microsoft.com" - 24 chars = 0x00000018
//      <end namespace length list>
//      <begin attribute headers>
//      <begin ENCODED_ASSEMBLY_IDENTITY_ATTRIBUTE_HEADER>
//      00000054:   00000001            NamespaceIndex: 1 (http://www.amazon.com)
//      00000058:   00000004            Name length ("name" - 4 chars = 0x00000004)
//      0000005C:   00000006            Value length ("foobar" - 6 chars = 0x00000006)
//      <end ENCODED_ASSEMBLY_IDENTITY_ATTRIBUTE_HEADER>
//      <begin ENCODED_ASSEMBLY_IDENTITY_ATTRIBUTE_HEADER>
//      00000060:   00000002            NamespaceIndex: 2 (http://www.microsoft.com)
//      00000064:   00000004            Name length ("guid" - 4 chars = 0x00000004)
//      00000068:   00000026            Value length ("{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" - 38 chars = 0x00000026)
//      <end ENCODED_ASSEMBLY_IDENTITY_ATTRIBUTE_HEADER>
//      <begin ENCODED_ASSEMBLY_IDENTITY_ATTRIBUTE_HEADER>
//      0000006C:   00000002            NamespaceIndex: 2 (http://www.microsoft.com)
//      00000070:   00000004            Name length ("type" - 4 chars = 0x00000004)
//      00000074:   00000005            Value length ("win32" - 5 chars = 0x00000005)
//      <end ENCODED_ASSEMBLY_IDENTITY_ATTRIBUTE_HEADER>
//      <end attribute headers>
//      <begin namespace strings>
//      00000078:   "http://www.amazon.com"
//      000000A2:   "http://www.microsoft.com"
//      <end namespace strings>
//      <begin attribute values - names and values for each attribute in series>
//      000000D2:   "name"
//      000000DA:   "foobar"
//      000000E6:   "guid"
//      000000EE:   "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"
//      0000013A:   "type"
//      00000142:   "win32"
//      <end attribute values>
//      0000014C:
//
//  Computing the whole identity hash:
//
//      The hash of the entire encoded identity is not the hash of the binary form, but
//      rather is a combination of the hashes for the various components.
//
//      For any Unicode character string, its hash is computed according to HashAlgorithm.
//      Currently this must be HASH_STRING_ALGORITHM_X65599 which is a multiply-and-
//      accumulate algorithm, implemented essentially as follows:
//
//          HashValue = 0;
//          for (i=0; i<Chars; i++)
//              HashValue = (HashValue * 65599) + OptionalToUpper(String[i]);
//
//      Note that the characters are converted to upper case.  This is somewhat in
//      conflict with the Unicode recommendation to convert to lower case for case
//      insensitive operations, but it is what the rest of the Windows NT system
//      does, so consistency matters more than doing the "right thing".
//
//      Note also that no trailing null characters are included in the hash.  This
//      is significant because of the fact that applying the loop to another character
//      even though its value is zero will significantly change the hash value.
//
//      Namespaces and attribute names are case sensitive, derived from the fact
//      that they appear in case sensitive contexts in the real world.  This is
//      unfortunate, but simpler in many ways.
//
//      Assembly identity attributes are composed of a triple of:
//          - Namespace URI (e.g. http://www.microsoft.com/schemas/side-by-side)
//          - Name (e.g. "publicKey")
//          - Value (case insensitive Unicode string)
//
//      The hash of an attribute is computed by computing the hash of the three
//      strings, and then combining them as:
//
//          AttributeHashValue = (((NamespaceHash * 65599) + NameHash) * 65599) + ValueHash
//
//      Now, sort the attributes based first on namespace, then on name then on
//      value (case sensitive, case sensitive and case insensitive respectively),
//      and combine their hashes as follows:
//
//          IdentityHash = 0;
//          for (i=0; i<AttributeCount; i++)
//              IdentityHash = (IdentityHash * 65599) + AttributeHashes[i];
//
//      IdentityHash is the value stored in the encoded header.
//
//      The attribute hash array stored in the encoded data is the attribute
//      hashes as described above.  The interesting thing is that they are stored
//      in order of ascending hash value, not in the canonical ordering for
//      attributes.
//
//      This is because a common scenario is to find an identity which has a
//      superset of a given identity.  While the actual attributes have to
//      be consulted to verify that the candidate is a true subset, non-
//      matches can be very quickly found by sorting both lists of hash
//      values and first looping over the smaller reference list, then
//      in a single pass walking the larger definition list.  Attributes present
//      in one but not in the other will be immediately noticable due to
//      the missing hashes.
//
//      As always with hashes, just because an encoded identity contains a
//      superset of the hash values in your candidate assembly reference,
//      it does not mean that the actual values appear and you must perform
//      real character string comparisons to verify containment.
//

#include <pshpack4.h>

typedef struct _ENCODED_ASSEMBLY_IDENTITY_HEADER {
    ULONG HeaderSize;           // bytes just in the header
    ULONG Magic;
    ULONG TotalSize;            // bytes for the whole encoded thing
    DWORD Flags;                // as defined for assembly identity flags
    ULONG Type;                 // type of identity - def, ref or wildcard
    ULONG EncodingFlags;        // flags describing the encoding itself
    ULONG HashAlgorithm;        // Algorithm ID for the hashes stored in the identity
    ULONG Hash;                 // Hash value of the entire identity
    ULONG AttributeCount;       // number of attributes
    ULONG NamespaceCount;       // number of distinct namespaces
    ULONG ReservedMustBeZero1;
    ULONG ReservedMustBeZero2;
    ULONGLONG ReservedMustBeZero3;
    ULONGLONG ReservedMustBeZero4;
} ENCODED_ASSEMBLY_IDENTITY_HEADER, *PENCODED_ASSEMBLY_IDENTITY_HEADER;

typedef const ENCODED_ASSEMBLY_IDENTITY_HEADER *PCENCODED_ASSEMBLY_IDENTITY_HEADER;

typedef struct _ENCODED_ASSEMBLY_IDENTITY_ATTRIBUTE_HEADER {
    ULONG NamespaceIndex;       // number of the namespace for this attribute
    ULONG NameCch;              // size in Unicode characters of the name immediately following the
                                // namespace
    ULONG ValueCch;             // size in Unicode characters of the value immediately following the
                                // name.
} ENCODED_ASSEMBLY_IDENTITY_ATTRIBUTE_HEADER, *PENCODED_ASSEMBLY_IDENTITY_ATTRIBUTE_HEADER;

typedef const ENCODED_ASSEMBLY_IDENTITY_ATTRIBUTE_HEADER *PCENCODED_ASSEMBLY_IDENTITY_ATTRIBUTE_HEADER;

#include <poppack.h>

#define SXSP_VALIDATE_ASSEMBLY_IDENTITY_FLAGS_MAY_BE_NULL (0x00000001)

BOOL
SxspValidateAssemblyIdentity(
    IN DWORD Flags,
    IN PCASSEMBLY_IDENTITY AssemblyIdentity
    );

BOOL
SxspValidateAssemblyIdentityAttributeNamespace(
    IN DWORD Flags,
    IN const WCHAR *Namespace,
    IN SIZE_T NamespaceCch
    );

BOOL
SxspValidateAssemblyIdentityAttributeName(
    IN DWORD Flags,
    IN const WCHAR *Name,
    IN SIZE_T NameCch
    );

#define SXSP_VALIDATE_ASSEMBLY_IDENTITY_ATTRIBUTE_VALUE_FLAG_WILDCARDS_PERMITTED (0x00000001)

BOOL
SxspValidateAssemblyIdentityAttributeValue(
    IN DWORD Flags,
    IN const WCHAR *Value,
    IN SIZE_T ValueCch
    );

BOOL
SxspComputeInternalAssemblyIdentityAttributeBytesRequired(
    IN DWORD Flags,
    IN const WCHAR *Name,
    IN SIZE_T NameCch,
    IN const WCHAR *Value,
    IN SIZE_T ValueCch,
    OUT SIZE_T *BytesRequiredOut
    );

BOOL
SxspComputeAssemblyIdentityAttributeBytesRequired(
    IN DWORD Flags,
    IN PCASSEMBLY_IDENTITY_ATTRIBUTE Source,
    OUT SIZE_T *BytesRequiredOut
    );

#define SXSP_FIND_ASSEMBLY_IDENTITY_NAMESPACE_IN_ARRAY_FLAG_ADD_IF_NOT_FOUND (0x00000001)

BOOL
SxspFindAssemblyIdentityNamespaceInArray(
    IN DWORD Flags,
    IN OUT PCASSEMBLY_IDENTITY_NAMESPACE **NamespacePointerArrayPtr,
    IN OUT ULONG *NamespaceArraySizePtr,
    IN OUT ULONG *NamespaceCountPtr,
    IN const WCHAR *Namespace,
    IN SIZE_T NamespaceCch,
    OUT PCASSEMBLY_IDENTITY_NAMESPACE *NamespaceOut
    );

#define SXSP_FIND_ASSEMBLY_IDENTITY_NAMESPACE_FLAG_ADD_IF_NOT_FOUND (0x00000001)

BOOL
SxspFindAssemblyIdentityNamespace(
    IN DWORD Flags,
    IN struct _ASSEMBLY_IDENTITY* AssemblyIdentity,
    IN const WCHAR *Namespace,
    IN SIZE_T NamespaceCch,
    OUT PCASSEMBLY_IDENTITY_NAMESPACE *NamespaceOut
    );

BOOL
SxspAllocateAssemblyIdentityNamespace(
    IN DWORD Flags,
    IN const WCHAR *NamespaceString,
    IN SIZE_T NamespaceCch,
    IN ULONG NamespaceHash,
    OUT PCASSEMBLY_IDENTITY_NAMESPACE *NamespaceOut
    );

VOID
SxspDeallocateAssemblyIdentityNamespace(
    IN PCASSEMBLY_IDENTITY_NAMESPACE Namespace
    );

BOOL
SxspPopulateInternalAssemblyIdentityAttribute(
    IN DWORD Flags,
    IN PCASSEMBLY_IDENTITY_NAMESPACE Namespace,
    IN const WCHAR *Name,
    IN SIZE_T NameCch,
    IN const WCHAR *Value,
    IN SIZE_T ValueCch,
    OUT PINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE Destination
    );

BOOL
SxspAllocateInternalAssemblyIdentityAttribute(
    IN DWORD Flags,
    IN PCASSEMBLY_IDENTITY_NAMESPACE Namespace,
    IN const WCHAR *Name,
    IN SIZE_T NameCch,
    IN const WCHAR *Value,
    IN SIZE_T ValueCch,
    OUT PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE *Destination
    );

VOID
SxspCleanUpAssemblyIdentityNamespaceIfNotReferenced(
    IN DWORD Flags,
    IN struct _ASSEMBLY_IDENTITY* AssemblyIdentity,
    IN PCASSEMBLY_IDENTITY_NAMESPACE Namespace
    );

VOID
SxspDeallocateInternalAssemblyIdentityAttribute(
    PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE Attribute
    );

int
__cdecl
SxspCompareInternalAttributesForQsort(
    const void *elem1,
    const void *elem2
    );

int
__cdecl
SxspCompareULONGsForQsort(
    const void *elem1,
    const void *elem2
    );

BOOL
SxspCompareAssemblyIdentityAttributeLists(
    DWORD Flags,
    ULONG AttributeCount,
    PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE *List1,
    PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE *List2,
    ULONG *ComparisonResultOut
    );

BOOL
SxspHashInternalAssemblyIdentityAttributes(
    DWORD Flags,
    ULONG Count,
    PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE *Attributes,
    ULONG *HashOut
    );

BOOL
SxspCopyInternalAssemblyIdentityAttributeOut(
    DWORD Flags,
    PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE Attribute,
    SIZE_T BufferSize,
    PASSEMBLY_IDENTITY_ATTRIBUTE DestinationBuffer,
    SIZE_T *BytesCopiedOrRequired
    );

BOOL
SxspIsInternalAssemblyIdentityAttribute(
    IN DWORD Flags,
    IN PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE Attribute,
    IN const WCHAR *Namespace,
    IN SIZE_T NamespaceCch,
    IN const WCHAR *Name,
    IN SIZE_T NameCch,
    OUT BOOL *EqualsOut
    );

#define SXSP_COMPUTE_INTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE_ENCODED_TEXTUAL_SIZE_FLAG_VALUE_ONLY (0x00000001)
#define SXSP_COMPUTE_INTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE_ENCODED_TEXTUAL_SIZE_FLAG_OMIT_QUOTES (0x00000002)

BOOL
SxspComputeInternalAssemblyIdentityAttributeEncodedTextualSize(
    IN DWORD Flags,
    IN PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE Attribute,
    OUT SIZE_T *BytesOut
    );

#define SXSP_LOCATE_INTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE_FLAG_MATCH_NAMESPACE   (0x00000001)
#define SXSP_LOCATE_INTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE_FLAG_MATCH_NAME        (0x00000002)
#define SXSP_LOCATE_INTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE_FLAG_MATCH_VALUE       (0x00000004)
#define SXSP_LOCATE_INTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE_FLAG_NOT_FOUND_RETURNS_NULL (0x00000008)

BOOL
SxspLocateInternalAssemblyIdentityAttribute(
    IN DWORD Flags,
    IN PCASSEMBLY_IDENTITY AssemblyIdentity,
    IN PCASSEMBLY_IDENTITY_ATTRIBUTE Attribute,
    OUT PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE *InternalAttributeOut,
    OUT ULONG *LastIndexSearched OPTIONAL
    );

BOOL
SxspComputeQuotedStringSize(
    IN DWORD Flags,
    IN const WCHAR *StringIn,
    IN SIZE_T Cch,
    OUT SIZE_T *BytesOut
    );

VOID
SxspDbgPrintInternalAssemblyIdentityAttribute(
    DWORD dwflags,
    PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE Attribute
    );

VOID
SxspDbgPrintInternalAssemblyIdentityAttributes(
    DWORD dwflags,
    ULONG AttributeCount,
    PCINTERNAL_ASSEMBLY_IDENTITY_ATTRIBUTE const *Attributes
    );

VOID
SxspDbgPrintAssemblyIdentityAttribute(
    DWORD dwflags,
    PCASSEMBLY_IDENTITY_ATTRIBUTE Attribute
    );

VOID
SxspDbgPrintAssemblyIdentityAttributes(
    DWORD dwflags,
    ULONG AttributeCount,
    PCASSEMBLY_IDENTITY_ATTRIBUTE const *Attributes
    );

BOOL
SxspEnsureAssemblyIdentityHashIsUpToDate(
    DWORD dwFlags,
    PCASSEMBLY_IDENTITY AssemblyIdentity
    );

#endif