diff options
Diffstat (limited to 'src/md/datablob.h')
-rw-r--r-- | src/md/datablob.h | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/src/md/datablob.h b/src/md/datablob.h new file mode 100644 index 0000000000..5fcbc4370d --- /dev/null +++ b/src/md/datablob.h @@ -0,0 +1,231 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// +// File: DataBlob.h +// + +// +// Class code:MetaData::DataBlob provides secure access to a block of memory from MetaData (i.e. with fixed +// endianess). +// +// ====================================================================================== + +#pragma once + +#include "external.h" + +namespace MetaData +{ + +// -------------------------------------------------------------------------------------- +// +// This class provides secure access to a block of memory. +// +class DataBlob +{ +private: + // + // Private data + // + + // The memory block of size code:m_cbSize. Can be non-NULL even if code:m_cbSize is 0. + __field_bcount(m_cbSize) + BYTE *m_pbData; + // Size of the memory block starting at code:m_pbData. If it is 0, then value of code:m_pbData can be + // anything (incl. NULL). + UINT32 m_cbSize; + +public: + // + // Initialization + // + + // Creates empty memory block. + inline DataBlob(); + // Creates memory block (pbData, of size cbSize). + inline DataBlob( + __in_bcount_opt(cbSize) BYTE *pbData, + UINT32 cbSize); + // Creates memory block copy. + inline DataBlob( + const DataBlob &source); + // Initializes memory block to empty data. The object could be already initialzied. + inline void Clear(); + // Initializes memory block to data (pbData, of size cbSize). The object should be empty before. + inline void Init( + __in_bcount_opt(cbSize) BYTE *pbData, + UINT32 cbSize); + + // + // Getters + // + + //#PeekUx_Functions + // Reads the U1/U2/U4/U8 from the data blob without skipping the read data. + // Returns FALSE if there's not enough data in the blob, doesn't initialize the value '*pnValue' then. + // Returns TRUE otherwise, fills *pnValue, but doesn't move the memory block (doesn't skip the read + // data). + __checkReturn __success(return) inline BOOL PeekU1(__out BYTE *pnValue) const; + __checkReturn __success(return) inline BOOL PeekU2(__out UINT16 *pnValue) const; + __checkReturn __success(return) inline BOOL PeekU4(__out UINT32 *pnValue) const; + __checkReturn __success(return) inline BOOL PeekU8(__out UINT64 *pnValue) const; + + //#GetUx_Functions + // Reads the U1/U2/U4/U8 from the data blob and skips the read data. + // Returns FALSE if there's not enough data in the blob, doesn't initialize the value '*pnValue' then. + // Returns TRUE otherwise, fills *pnValue and moves the memory block behind the read data. + __checkReturn __success(return) inline BOOL GetU1(__out BYTE *pnValue); + __checkReturn __success(return) inline BOOL GetU2(__out UINT16 *pnValue); + __checkReturn __success(return) inline BOOL GetU4(__out UINT32 *pnValue); + __checkReturn __success(return) inline BOOL GetU8(__out UINT64 *pnValue); + + // Reads compressed integer (1, 2 or 4 bytes of format code:CompressedInteger#Format - returns the size + // in *pcbCompressedValueSize) from the data blob without skipping the read data. + // Returns FALSE if there's not enough data in the blob or the compression is invalid (starts with byte + // 111? ????), doesn't initialize the value *pnValue nor the size of the compressed value + // *pcbCompressedValueSize then. + // Returns TRUE otherwise, fills *pnValue and *pcbCompressedValueSize (with number 1,2 or 4), but + // doesn't move the memory block (doesn't skip the read data). + __checkReturn + __success(return) + inline BOOL PeekCompressedU( + __out UINT32 *pnValue, + __out UINT32 *pcbCompressedValueSize); + // Reads compressed integer (1, 2 or 4 bytes of format code:CompressedInteger#Format) from the data blob + // and skips the read data. + // Returns FALSE if there's not enough data in the blob or the compression is invalid (starts with byte + // 111? ????), doesn't initialize the value *pnValue then. + // Returns TRUE otherwise, fills *pnValue and moves the memory block behind the read data. + __checkReturn + __success(return) + inline BOOL GetCompressedU(__out UINT32 *pnValue); + // Reads compressed integer (1, 2 or 4 bytes of format code:CompressedInteger#Format - returns the size + // in *pcbCompressedValueSize) from the data blob and skips the read data. + // Returns FALSE if there's not enough data in the blob or the compression is invalid (starts with byte + // 111? ????), doesn't initialize the value *pnValue nor the size of the compressed value + // *pcbCompressedValueSize then. + // Returns TRUE otherwise, fills *pnValue and *pcbCompressedValueSize (with number 1,2 or 4) and moves + // the memory block behind the read data. + __checkReturn + __success(return) + inline BOOL GetCompressedU( + __out UINT32 *pnValue, + __out UINT32 *pcbCompressedValueSize); + + // Reads data of size cbDataSize and skips the data (instead of reading the bytes, returns the data as + // *pData). + // Returns FALSE if there's not enough data in the blob, clears *pData then. + // Returns TRUE otherwise, fills *pData with the "read" data and moves the memory block behind the + // "read" data. + __checkReturn + __success(return) + inline BOOL GetDataOfSize( + UINT32 cbDataSize, + __out DataBlob *pData); + + // Checks if there's at least cbDataSize bytes in the represented memory block. + // Returns TRUE if there's >= cbDataSize bytes. Returns FALSE otherwise. + inline BOOL ContainsData(UINT32 cbDataSize) const + { return cbDataSize <= m_cbSize; } +/* + // Checks if there's at least cbDataSize1 + cbDataSize2 bytes in the represented memory block (and that + // the sum doesn't overflow). + // Returns TRUE if there's >= cbDataSize1 + cbDataSize2 bytes. + // Returns FALSE otherwise and if cbDataSize1 + cbDataSize2 overflows. + inline BOOL ContainsData_2Parts( + UINT32 cbDataSize1, + UINT32 cbDataSize2) const; + // Checks if there's valid compressed integer (1, 2 or 4 bytes of format + // code:DataBlob#CompressedIntegerFormat) in the data blob. + // Returns: + // * 0 ... if there's valid compressed integer. + // * 1 ... if there's not enough data in the data blob, but the encoding is correct. + // * 2 ... if the integer encoding is invalid (starts with byte 111x xxxx byte), but there are at least + // 4 bytes in the data blob left. + // * 3 ... if there's not enough data in the data blob and the integer encoding is invalid (starts with + // 111x xxx byte). + inline int ValidateCompressedU() const; +*/ + + // Returns TRUE if the represented memory is empty. + inline BOOL IsEmpty() const + { return (m_cbSize == 0); } + // Gets pointer to the represented data buffer (can be random pointer if size of the data is 0). + // Note: Should be used exceptionally. Try to use other operations instead. + inline BYTE *GetDataPointer() + { return m_pbData; } + // Gets pointer to the represented data buffer (can be random pointer if size of the data is 0). + // Note: Should be used exceptionally. Try to use other operations instead. + inline const BYTE *GetDataPointer() const + { return m_pbData; } + // Gets pointer right behind the represented data buffer (can be random pointer if size of the data is + // 0). + inline const BYTE *GetDataPointerBehind() const + { return ((m_cbSize == 0) ? NULL : (m_pbData + m_cbSize)); } + // Gets the size of represented memory. + inline UINT32 GetSize() const + { return m_cbSize; } + //BOOL SkipBytes(UINT32 cbSize); + +public: + // + // Operations + // + + // Truncates the buffer to exact size (cbSize). + // Returns FALSE if there's less than cbSize data represented. + // Returns TRUE otherwise and truncates the represented data size to cbSize. + __checkReturn + __success(return) + inline BOOL TruncateToExactSize(UINT32 cbSize); + // Truncates the buffer by size (cbSize). + // Returns FALSE if there's less than cbSize data represented. + // Returns TRUE otherwise and truncates the represented data size by cbSize. + __checkReturn + __success(return) + inline BOOL TruncateBySize(UINT32 cbSize); + +#ifdef _DEBUG + // Returns U1 value at offset (nOffset). Fires an assert if the offset is behind the end of represented + // data. + inline BYTE Debug_GetByteAtOffset(UINT32 nOffset) const; +#endif //_DEBUG + +public: + // + // Setters + // + + // Writes compressed integer (1, 2 or 4 bytes of format code:CompressedInteger#Format) to the data blob + // and skips the written data. + // Returns FALSE if there's not enough data in the blob or the value cannot be encoded as compressed + // integer (bigger than code:CompressedInteger::const_Max). + // Returns TRUE on success and moves the memory block behind the written data. + __checkReturn + __success(return) + inline BOOL StoreCompressedU(UINT32 nValue); + + // Writes data from *pSource to the data blob and skips the written data. + // Returns FALSE if there's not enough data in the blob. + // Returns TRUE on success and moves memory block behind the written data. + __checkReturn + __success(return) + inline BOOL StoreData(__in const DataBlob *pSource); + +private: + // + // Helpers + // + + // Skips cbSize bytes in the represented memory block. The caller is responsible for making sure that + // the represented memory block contains at least cbSize bytes, otherwise there will be a security + // issue. + // Should be used only internally, never call it from outside of this class. + inline void SkipBytes_InternalInsecure(UINT32 cbSize); + +}; // class DataBlob + +}; // namespace MetaData + +#include "datablob.inl" |