#include "pch.h"
#include <iostream>
#include <Windows.h>
#define VAL32(x) x
#define VAL16(x) x
#define DPTR(type) type*
typedef DPTR(IMAGE_DOS_HEADER) PTR_IMAGE_DOS_HEADER;
typedef DPTR(IMAGE_NT_HEADERS) PTR_IMAGE_NT_HEADERS;
typedef DPTR(IMAGE_NT_HEADERS64) PTR_IMAGE_NT_HEADERS64;
typedef ULONG_PTR TADDR;
typedef DPTR(IMAGE_DATA_DIRECTORY) PTR_IMAGE_DATA_DIRECTORY;
typedef void* PTR_VOID;
typedef DPTR(IMAGE_COR20_HEADER) PTR_IMAGE_COR20_HEADER;
typedef CONST void far *LPCVOID;
template <typename Tgt, typename Src>
inline Tgt dac_cast(Src src)
{
#ifdef DACCESS_COMPILE
// In DAC builds, first get a TADDR for the source, then create the
// appropriate destination instance.
TADDR addr = dac_imp::getTaddr(src);
return dac_imp::makeDacInst<Tgt>::fromTaddr(addr);
#else
// In non-DAC builds, dac_cast is the same as a C-style cast because we need to support:
// - casting away const
// - conversions between pointers and TADDR
// Perhaps we should more precisely restrict it's usage, but we get the precise
// restrictions in DAC builds, so it wouldn't buy us much.
return (Tgt)(src);
#endif
}
TADDR m_base;
TADDR m_b;
#define ALIGN4BYTE(val) (((val) + 3) & ~0x3)
struct STORAGEHEADER
{
public:
BYTE fFlags; // STGHDR_xxx flags.
BYTE pad;
USHORT iStreams; // How many streams are there.
public:
BYTE GetFlags()
{
return fFlags;
}
void SetFlags(BYTE flags)
{
fFlags = flags;
}
void AddFlags(BYTE flags)
{
fFlags |= flags;
}
USHORT GetiStreams()
{
return VAL16(iStreams);
}
void SetiStreams(USHORT iStreamsCount)
{
iStreams = VAL16(iStreamsCount);
}
};
struct STORAGESIGNATURE
{
public:
ULONG lSignature; // "Magic" signature.
USHORT iMajorVer; // Major file version.
USHORT iMinorVer; // Minor file version.
ULONG iExtraData; // Offset to next structure of information
ULONG iVersionString; // Length of version string
public:
BYTE pVersion[0]; // Version string
ULONG GetSignature()
{
return VAL32(lSignature);
}
void SetSignature(ULONG Signature)
{
lSignature = VAL32(Signature);
}
USHORT GetMajorVer()
{
return VAL16(iMajorVer);
}
void SetMajorVer(USHORT MajorVer)
{
iMajorVer = VAL16(MajorVer);
}
USHORT GetMinorVer()
{
return VAL16(iMinorVer);
}
void SetMinorVer(USHORT MinorVer)
{
iMinorVer = VAL16(MinorVer);
}
ULONG GetExtraDataOffset()
{
return VAL32(iExtraData);
}
void SetExtraDataOffset(ULONG ExtraDataOffset)
{
iExtraData = VAL32(ExtraDataOffset);
}
ULONG GetVersionStringLength()
{
return VAL32(iVersionString);
}
void SetVersionStringLength(ULONG VersionStringLength)
{
iVersionString = VAL32(VersionStringLength);
}
};
struct PSTORAGESIGNATURE
{
public:
ULONG lSignature; // "Magic" signature.
USHORT iMajorVer; // Major file version.
USHORT iMinorVer; // Minor file version.
ULONG iExtraData; // Offset to next structure of information
ULONG iVersionString; // Length of version string
public:
BYTE pVersion[0]; // Version string
ULONG GetSignature()
{
return VAL32(lSignature);
}
void SetSignature(ULONG Signature)
{
lSignature = VAL32(Signature);
}
USHORT GetMajorVer()
{
return VAL16(iMajorVer);
}
void SetMajorVer(USHORT MajorVer)
{
iMajorVer = VAL16(MajorVer);
}
USHORT GetMinorVer()
{
return VAL16(iMinorVer);
}
void SetMinorVer(USHORT MinorVer)
{
iMinorVer = VAL16(MinorVer);
}
ULONG GetExtraDataOffset()
{
return VAL32(iExtraData);
}
void SetExtraDataOffset(ULONG ExtraDataOffset)
{
iExtraData = VAL32(ExtraDataOffset);
}
ULONG GetVersionStringLength()
{
return VAL32(iVersionString);
}
void SetVersionStringLength(ULONG VersionStringLength)
{
iVersionString = VAL32(VersionStringLength);
}
};
struct STORAGESTREAM;
typedef STORAGESTREAM UNALIGNED * PSTORAGESTREAM;
struct STORAGESTREAM
{
public:
ULONG iOffset; // Offset in file for this stream.
ULONG iSize; // Size of the file.
char rcName[32]; // Start of name, null terminated.
public:
// Returns pointer to the next stream. Doesn't validate the structure.
inline PSTORAGESTREAM NextStream()
{
int iLen = (int)(strlen(rcName) + 1);
iLen = ALIGN4BYTE(iLen);
return ((PSTORAGESTREAM)(((BYTE*)this) + (sizeof(ULONG) * 2) + iLen));
}
// Returns pointer to the next stream.
// Returns NULL if the structure has invalid format.
inline PSTORAGESTREAM NextStream_Verify()
{
// Check existence of null-terminator in the name
if (memchr(rcName, 0, 32) == NULL)
{
return NULL;
}
return NextStream();
}
inline ULONG GetStreamSize()
{
return (ULONG)(strlen(rcName) + 1 + (sizeof(STORAGESTREAM) - sizeof(rcName)));
}
inline char* GetName()
{
return rcName;
}
inline LPCWSTR GetName(__inout_ecount(iMaxSize) LPWSTR szName, int iMaxSize)
{
//VERIFY(::WszMultiByteToWideChar(CP_ACP, 0, rcName, -1, szName, iMaxSize));
return (szName);
}
inline void SetName(LPCWSTR szName)
{
int size;
//size = WszWideCharToMultiByte(CP_ACP, 0, szName, -1, rcName, MAXSTREAMNAME, 0, 0);
_ASSERTE(size > 0);
}
ULONG GetSize()
{
return VAL32(iSize);
}
void SetSize(ULONG Size)
{
iSize = VAL32(Size);
}
ULONG GetOffset()
{
return VAL32(iOffset);
}
void SetOffset(ULONG Offset)
{
iOffset = VAL32(Offset);
}
};
#define UI64_HELPER(x) x ## ui64
#define UI64(x) UI64_HELPER(x)
class CMiniMdSchemaBase
{
public:
ULONG m_ulReserved; // Reserved, must be zero.
BYTE m_major; // Version numbers.
BYTE m_minor;
BYTE m_heaps; // Bits for heap sizes.
BYTE m_rid; // log-base-2 of largest rid.
// Bits for heap sizes.
enum {
HEAP_STRING_4 = 0x01,
HEAP_GUID_4 = 0x02,
HEAP_BLOB_4 = 0x04,
PADDING_BIT = 0x08, // Tables can be created with an extra bit in columns, for growth.
DELTA_ONLY = 0x20, // If set, only deltas were persisted.
EXTRA_DATA = 0x40, // If set, schema persists an extra 4 bytes of data.
HAS_DELETE = 0x80, // If set, this metadata can contain _Delete tokens.
};
unsigned __int64 m_maskvalid; // Bit mask of present table counts.
unsigned __int64 m_sorted; // Bit mask of sorted tables.
FORCEINLINE bool IsSorted(ULONG ixTbl)
{
return m_sorted & BIT(ixTbl) ? true : false;
}
void SetSorted(ULONG ixTbl, int bVal)
{
if (bVal) m_sorted |= BIT(ixTbl);
else m_sorted &= ~BIT(ixTbl);
}
#if BIGENDIAN
// Verify that the size hasn't changed (Update if necessary)
void ConvertEndianness()
{
_ASSERTE(sizeof(CMiniMdSchemaBase) == 0x18);
m_ulReserved = VAL32(m_ulReserved);
m_maskvalid = VAL64(m_maskvalid);
m_sorted = VAL64(m_sorted);
}
#else
// Nothing to do on little endian machine
void ConvertEndianness() { return; }
#endif
private:
FORCEINLINE unsigned __int64 BIT(ULONG ixBit)
{
_ASSERTE(ixBit < (sizeof(__int64)*CHAR_BIT));
return UI64(1) << ixBit;
}
};
typedef enum MetadataVersion
{
MDVersion1 = 0x00000001,
MDVersion2 = 0x00000002,
// @TODO - this value should be updated when we increase the version number
MDDefaultVersion = 0x00000002
} MetadataVersion;
class CMiniMdSchema : public CMiniMdSchemaBase
{
public:
// These are not all persisted to disk. See LoadFrom() for details.
ULONG m_cRecs[45]; // Counts of various tables.
ULONG m_ulExtra; // Extra data, only persisted if non-zero. (m_heaps&EXTRA_DATA flags)
ULONG LoadFrom(const void*, ULONG); // Load from a compressed version. Return bytes consumed.
ULONG SaveTo(void *); // Store a compressed version. Return bytes used in buffer.
__checkReturn
HRESULT InitNew(MetadataVersion);
};
#define GET_UNALIGNED_32(_pObject) (*(UINT32 UNALIGNED *)(_pObject))
#define GET_UNALIGNED_VAL32(_pObject) VAL32(GET_UNALIGNED_32(_pObject))
//template<typename T> class ClrSafeInt
//{
//public:
//