1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4//
5// File: DataBuffer.inl
6//
7
8//
9// Class code:DataBuffer provides secure access to a block of memory.
10//
11// ======================================================================================
12
13#pragma once
14
15#include "databuffer.h"
16
17// --------------------------------------------------------------------------------------
18//
19// Creates empty memory block.
20//
21inline
22DataBuffer::DataBuffer()
23{
24 Clear();
25} // DataBuffer::DataBuffer
26
27// --------------------------------------------------------------------------------------
28//
29// Creates memory block (pbData, of size cbSize).
30//
31inline
32DataBuffer::DataBuffer(
33 __in_bcount(cbSize) BYTE *pbData,
34 UINT32 cbSize)
35{
36 m_pbData = pbData;
37 m_cbSize = cbSize;
38} // DataBuffer::DataBuffer
39
40// --------------------------------------------------------------------------------------
41//
42// Creates memory block copy.
43//
44inline
45DataBuffer::DataBuffer(
46 const DataBuffer &source)
47{
48 m_pbData = source.m_pbData;
49 m_cbSize = source.m_cbSize;
50} // DataBuffer::DataBuffer
51
52#ifdef _WIN64
53 #define const_pbBadFood (((BYTE *)NULL) + 0xbaadf00dbaadf00d)
54#else //!_WIN64
55 #define const_pbBadFood (((BYTE *)NULL) + 0xbaadf00d)
56#endif //!_WIN64
57
58// --------------------------------------------------------------------------------------
59//
60// Initializes memory block to empty data. The object could be already initialzied.
61//
62inline
63void
64DataBuffer::Clear()
65{
66 m_cbSize = 0;
67 // For debugging purposes let's put invalid non-NULL pointer here
68 INDEBUG_MD(m_pbData = const_pbBadFood);
69} // DataBuffer::Clear
70
71#undef const_pbBadFood
72
73// --------------------------------------------------------------------------------------
74//
75// Initializes memory block to data (pbData, of size cbSize). The object should be empty before.
76//
77inline
78void
79DataBuffer::Init(
80 __in_bcount(cbSize) BYTE *pbData,
81 UINT32 cbSize)
82{
83 _ASSERTE(IsEmpty());
84
85 m_pbData = pbData;
86 m_cbSize = cbSize;
87} // DataBuffer::Init
88
89// --------------------------------------------------------------------------------------
90//
91// Reads data of type T without skipping the read data (returns pointer to the type in *ppTypeData).
92// Returns FALSE if there's not enough data (of size T) in the blob, doesn't initialize the pointer
93// *ppTypeData then.
94// Returns TRUE otherwise, fills *ppTypeData with the "read" type start, but doesn't move the memory
95// block (doesn't skip the "read" data).
96//
97template<class T>
98__checkReturn
99inline
100BOOL
101DataBuffer::PeekData(
102 __deref_out T **ppTypeData)
103{
104 if (m_cbSize < sizeof(T))
105 { // There's not enough data in the memory block
106 return FALSE;
107 }
108 // Fill the start of the "read" type
109 *ppTypeData = reinterpret_cast<T *>(m_pbData);
110 return TRUE;
111} // DataBuffer::PeekData
112
113// --------------------------------------------------------------------------------------
114//
115// Reads data of type T at offset nOffset without skipping the read data (returns pointer to the type in
116// *ppTypeData).
117// Returns FALSE if there's not enough data (of size T) at offset nOffset in the buffer, doesn't
118// initialize the pointer *ppTypeData then.
119// Returns TRUE otherwise, fills *ppTypeData with the type start, but doesn't move the memory block
120// (doesn't skip any "read" data).
121template<class T>
122__checkReturn
123inline
124BOOL
125DataBuffer::PeekDataAt(
126 UINT32 nOffset,
127 __deref_out T **ppTypeData)
128{
129 if (m_cbSize < nOffset)
130 { // The offset is not in the memory block
131 return FALSE;
132 }
133 if ((m_cbSize - nOffset) < sizeof(T))
134 { // The type is not fully in the memory block
135 return FALSE;
136 }
137 // Fill the start of the "read" type
138 *ppTypeData = reinterpret_cast<T *>(m_pbData + nOffset);
139 return TRUE;
140} // DataBuffer::PeekDataAt
141
142// --------------------------------------------------------------------------------------
143//
144// Reads data of type T and skips the data (instead of reading the bytes, returns pointer to the type in
145// *ppTypeData).
146// Returns FALSE if there's not enough data (of size T) in the blob, doesn't initialize the pointer
147// *ppTypeData then.
148// Returns TRUE otherwise, fills *ppTypeData with the "read" type start and moves the memory block
149// behind the "read" type.
150//
151template<class T>
152__checkReturn
153inline
154BOOL
155DataBuffer::GetData(
156 __deref_out T **ppTypeData)
157{
158 if (m_cbSize < sizeof(T))
159 { // There's not enough data in the memory block
160 return FALSE;
161 }
162 // Fill the start of the "read" type
163 *ppTypeData = reinterpret_cast<T *>(m_pbData);
164 SkipBytes_InternalInsecure(sizeof(T));
165 return TRUE;
166} // DataBuffer::GetData
167
168// --------------------------------------------------------------------------------------
169//
170// Reads data of size cbDataSize and skips the data (instead of reading the bytes, returns pointer to
171// the bytes in *ppbDataPointer).
172// Returns FALSE if there's not enough data in the blob, doesn't initialize the pointer *ppbDataPointer
173// then.
174// Returns TRUE otherwise, fills *ppbDataPointer with the "read" data start and moves the memory block
175// behind the "read" data.
176//
177__checkReturn
178inline
179BOOL
180DataBuffer::GetDataOfSize(
181 UINT32 cbDataSize,
182 __out_bcount(cbDataSize) BYTE **ppbDataPointer)
183{
184 if (m_cbSize < cbDataSize)
185 { // There's not enough data in the memory block
186 return FALSE;
187 }
188 // Fill the start of the "read" data
189 *ppbDataPointer = m_pbData;
190 SkipBytes_InternalInsecure(cbDataSize);
191 return TRUE;
192} // DataBuffer::GetDataOfSize
193
194// --------------------------------------------------------------------------------------
195//
196// Truncates the buffer to exact size (cbSize).
197// Returns FALSE if there's less than cbSize data represented.
198// Returns TRUE otherwise and truncates the represented data size to cbSize.
199//
200__checkReturn
201inline
202BOOL
203DataBuffer::TruncateToExactSize(UINT32 cbSize)
204{
205 // Check if there's at least cbSize data present
206 if (m_cbSize < cbSize)
207 { // There's less than cbSize data present
208 // Fail the operation
209 return FALSE;
210 }
211 // Truncate represented data to size cbSize
212 m_cbSize = cbSize;
213 return TRUE;
214} // DataBuffer::TruncateToExactSize
215
216// --------------------------------------------------------------------------------------
217//
218// Truncates the buffer by size (cbSize).
219// Returns FALSE if there's less than cbSize data represented.
220// Returns TRUE otherwise and truncates the represented data size by cbSize.
221//
222__checkReturn
223inline
224BOOL
225DataBuffer::TruncateBySize(UINT32 cbSize)
226{
227 // Check if there's at least cbSize data present
228 if (m_cbSize < cbSize)
229 { // There's less than cbSize data present
230 // Fail the operation
231 return FALSE;
232 }
233 // Truncate represented data by size cbSize
234 m_cbSize -= cbSize;
235 return TRUE;
236} // DataBuffer::TruncateBySize
237
238// --------------------------------------------------------------------------------------
239//
240// Skips the buffer to size (cbSize).
241// Returns FALSE if there's less than cbSize data represented.
242// Returns TRUE otherwise and skips data at the beggining, so that the result has size cbSize.
243//
244__checkReturn
245inline
246BOOL
247DataBuffer::SkipToExactSize(UINT32 cbSize)
248{
249 // Check if there's at least cbSize data present
250 if (m_cbSize < cbSize)
251 { // There's less than cbSize data present
252 // Fail the operation
253 return FALSE;
254 }
255 SkipBytes_InternalInsecure(m_cbSize - cbSize);
256 return TRUE;
257} // DataBuffer::SkipToExactSize
258
259// --------------------------------------------------------------------------------------
260//
261// Skips 'cbSize' bytes in the represented memory block. The caller is responsible for making sure that the
262// represented memory block contains at least 'cbSize' bytes, otherwise there will be a security issue.
263// Should be used only internally, never call it from outside of this class.
264//
265inline
266void
267DataBuffer::SkipBytes_InternalInsecure(UINT32 cbSize)
268{
269 // The caller is responsible for this check, just double check here
270 _ASSERTE(m_cbSize >= cbSize);
271 // Move the memory block by 'cbSize' bytes
272 m_pbData += cbSize;
273 m_cbSize -= cbSize;
274} // DataBuffer::SkipBytes_InternalInsecure
275