diff options
Diffstat (limited to 'src/md/databuffer.inl')
-rw-r--r-- | src/md/databuffer.inl | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/src/md/databuffer.inl b/src/md/databuffer.inl new file mode 100644 index 0000000000..e3a226e1f3 --- /dev/null +++ b/src/md/databuffer.inl @@ -0,0 +1,274 @@ +// 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: DataBuffer.inl +// + +// +// Class code:DataBuffer provides secure access to a block of memory. +// +// ====================================================================================== + +#pragma once + +#include "databuffer.h" + +// -------------------------------------------------------------------------------------- +// +// Creates empty memory block. +// +inline +DataBuffer::DataBuffer() +{ + Clear(); +} // DataBuffer::DataBuffer + +// -------------------------------------------------------------------------------------- +// +// Creates memory block (pbData, of size cbSize). +// +inline +DataBuffer::DataBuffer( + __in_bcount(cbSize) BYTE *pbData, + UINT32 cbSize) +{ + m_pbData = pbData; + m_cbSize = cbSize; +} // DataBuffer::DataBuffer + +// -------------------------------------------------------------------------------------- +// +// Creates memory block copy. +// +inline +DataBuffer::DataBuffer( + const DataBuffer &source) +{ + m_pbData = source.m_pbData; + m_cbSize = source.m_cbSize; +} // DataBuffer::DataBuffer + +#ifdef _WIN64 + #define const_pbBadFood (((BYTE *)NULL) + 0xbaadf00dbaadf00d) +#else //!_WIN64 + #define const_pbBadFood (((BYTE *)NULL) + 0xbaadf00d) +#endif //!_WIN64 + +// -------------------------------------------------------------------------------------- +// +// Initializes memory block to empty data. The object could be already initialzied. +// +inline +void +DataBuffer::Clear() +{ + m_cbSize = 0; + // For debugging purposes let's put invalid non-NULL pointer here + INDEBUG_MD(m_pbData = const_pbBadFood); +} // DataBuffer::Clear + +#undef const_pbBadFood + +// -------------------------------------------------------------------------------------- +// +// Initializes memory block to data (pbData, of size cbSize). The object should be empty before. +// +inline +void +DataBuffer::Init( + __in_bcount(cbSize) BYTE *pbData, + UINT32 cbSize) +{ + _ASSERTE(IsEmpty()); + + m_pbData = pbData; + m_cbSize = cbSize; +} // DataBuffer::Init + +// -------------------------------------------------------------------------------------- +// +// Reads data of type T without skipping the read data (returns pointer to the type in *ppTypeData). +// Returns FALSE if there's not enough data (of size T) in the blob, doesn't initialize the pointer +// *ppTypeData then. +// Returns TRUE otherwise, fills *ppTypeData with the "read" type start, but doesn't move the memory +// block (doesn't skip the "read" data). +// +template<class T> +__checkReturn +inline +BOOL +DataBuffer::PeekData( + __deref_out T **ppTypeData) +{ + if (m_cbSize < sizeof(T)) + { // There's not enough data in the memory block + return FALSE; + } + // Fill the start of the "read" type + *ppTypeData = reinterpret_cast<T *>(m_pbData); + return TRUE; +} // DataBuffer::PeekData + +// -------------------------------------------------------------------------------------- +// +// Reads data of type T at offset nOffset without skipping the read data (returns pointer to the type in +// *ppTypeData). +// Returns FALSE if there's not enough data (of size T) at offset nOffset in the buffer, doesn't +// initialize the pointer *ppTypeData then. +// Returns TRUE otherwise, fills *ppTypeData with the type start, but doesn't move the memory block +// (doesn't skip any "read" data). +template<class T> +__checkReturn +inline +BOOL +DataBuffer::PeekDataAt( + UINT32 nOffset, + __deref_out T **ppTypeData) +{ + if (m_cbSize < nOffset) + { // The offset is not in the memory block + return FALSE; + } + if ((m_cbSize - nOffset) < sizeof(T)) + { // The type is not fully in the memory block + return FALSE; + } + // Fill the start of the "read" type + *ppTypeData = reinterpret_cast<T *>(m_pbData + nOffset); + return TRUE; +} // DataBuffer::PeekDataAt + +// -------------------------------------------------------------------------------------- +// +// Reads data of type T and skips the data (instead of reading the bytes, returns pointer to the type in +// *ppTypeData). +// Returns FALSE if there's not enough data (of size T) in the blob, doesn't initialize the pointer +// *ppTypeData then. +// Returns TRUE otherwise, fills *ppTypeData with the "read" type start and moves the memory block +// behind the "read" type. +// +template<class T> +__checkReturn +inline +BOOL +DataBuffer::GetData( + __deref_out T **ppTypeData) +{ + if (m_cbSize < sizeof(T)) + { // There's not enough data in the memory block + return FALSE; + } + // Fill the start of the "read" type + *ppTypeData = reinterpret_cast<T *>(m_pbData); + SkipBytes_InternalInsecure(sizeof(T)); + return TRUE; +} // DataBuffer::GetData + +// -------------------------------------------------------------------------------------- +// +// Reads data of size cbDataSize and skips the data (instead of reading the bytes, returns pointer to +// the bytes in *ppbDataPointer). +// Returns FALSE if there's not enough data in the blob, doesn't initialize the pointer *ppbDataPointer +// then. +// Returns TRUE otherwise, fills *ppbDataPointer with the "read" data start and moves the memory block +// behind the "read" data. +// +__checkReturn +inline +BOOL +DataBuffer::GetDataOfSize( + UINT32 cbDataSize, + __out_bcount(cbDataSize) BYTE **ppbDataPointer) +{ + if (m_cbSize < cbDataSize) + { // There's not enough data in the memory block + return FALSE; + } + // Fill the start of the "read" data + *ppbDataPointer = m_pbData; + SkipBytes_InternalInsecure(cbDataSize); + return TRUE; +} // DataBuffer::GetDataOfSize + +// -------------------------------------------------------------------------------------- +// +// 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 +inline +BOOL +DataBuffer::TruncateToExactSize(UINT32 cbSize) +{ + // Check if there's at least cbSize data present + if (m_cbSize < cbSize) + { // There's less than cbSize data present + // Fail the operation + return FALSE; + } + // Truncate represented data to size cbSize + m_cbSize = cbSize; + return TRUE; +} // DataBuffer::TruncateToExactSize + +// -------------------------------------------------------------------------------------- +// +// 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 +inline +BOOL +DataBuffer::TruncateBySize(UINT32 cbSize) +{ + // Check if there's at least cbSize data present + if (m_cbSize < cbSize) + { // There's less than cbSize data present + // Fail the operation + return FALSE; + } + // Truncate represented data by size cbSize + m_cbSize -= cbSize; + return TRUE; +} // DataBuffer::TruncateBySize + +// -------------------------------------------------------------------------------------- +// +// Skips the buffer to size (cbSize). +// Returns FALSE if there's less than cbSize data represented. +// Returns TRUE otherwise and skips data at the beggining, so that the result has size cbSize. +// +__checkReturn +inline +BOOL +DataBuffer::SkipToExactSize(UINT32 cbSize) +{ + // Check if there's at least cbSize data present + if (m_cbSize < cbSize) + { // There's less than cbSize data present + // Fail the operation + return FALSE; + } + SkipBytes_InternalInsecure(m_cbSize - cbSize); + return TRUE; +} // DataBuffer::SkipToExactSize + +// -------------------------------------------------------------------------------------- +// +// 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 +DataBuffer::SkipBytes_InternalInsecure(UINT32 cbSize) +{ + // The caller is responsible for this check, just double check here + _ASSERTE(m_cbSize >= cbSize); + // Move the memory block by 'cbSize' bytes + m_pbData += cbSize; + m_cbSize -= cbSize; +} // DataBuffer::SkipBytes_InternalInsecure |