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: DataBlob.h |
6 | // |
7 | |
8 | // |
9 | // Class code:MetaData::DataBlob provides secure access to a block of memory from MetaData (i.e. with fixed |
10 | // endianess). |
11 | // |
12 | // ====================================================================================== |
13 | |
14 | #pragma once |
15 | |
16 | #include "external.h" |
17 | |
18 | namespace MetaData |
19 | { |
20 | |
21 | // -------------------------------------------------------------------------------------- |
22 | // |
23 | // This class provides secure access to a block of memory. |
24 | // |
25 | class DataBlob |
26 | { |
27 | private: |
28 | // |
29 | // Private data |
30 | // |
31 | |
32 | // The memory block of size code:m_cbSize. Can be non-NULL even if code:m_cbSize is 0. |
33 | __field_bcount(m_cbSize) |
34 | BYTE *m_pbData; |
35 | // Size of the memory block starting at code:m_pbData. If it is 0, then value of code:m_pbData can be |
36 | // anything (incl. NULL). |
37 | UINT32 m_cbSize; |
38 | |
39 | public: |
40 | // |
41 | // Initialization |
42 | // |
43 | |
44 | // Creates empty memory block. |
45 | inline DataBlob(); |
46 | // Creates memory block (pbData, of size cbSize). |
47 | inline DataBlob( |
48 | __in_bcount_opt(cbSize) BYTE *pbData, |
49 | UINT32 cbSize); |
50 | // Creates memory block copy. |
51 | inline DataBlob( |
52 | const DataBlob &source); |
53 | // Initializes memory block to empty data. The object could be already initialzied. |
54 | inline void Clear(); |
55 | // Initializes memory block to data (pbData, of size cbSize). The object should be empty before. |
56 | inline void Init( |
57 | __in_bcount_opt(cbSize) BYTE *pbData, |
58 | UINT32 cbSize); |
59 | |
60 | // |
61 | // Getters |
62 | // |
63 | |
64 | //#PeekUx_Functions |
65 | // Reads the U1/U2/U4/U8 from the data blob without skipping the read data. |
66 | // Returns FALSE if there's not enough data in the blob, doesn't initialize the value '*pnValue' then. |
67 | // Returns TRUE otherwise, fills *pnValue, but doesn't move the memory block (doesn't skip the read |
68 | // data). |
69 | __checkReturn __success(return) inline BOOL PeekU1(__out BYTE *pnValue) const; |
70 | __checkReturn __success(return) inline BOOL PeekU2(__out UINT16 *pnValue) const; |
71 | __checkReturn __success(return) inline BOOL PeekU4(__out UINT32 *pnValue) const; |
72 | __checkReturn __success(return) inline BOOL PeekU8(__out UINT64 *pnValue) const; |
73 | |
74 | //#GetUx_Functions |
75 | // Reads the U1/U2/U4/U8 from the data blob and skips the read data. |
76 | // Returns FALSE if there's not enough data in the blob, doesn't initialize the value '*pnValue' then. |
77 | // Returns TRUE otherwise, fills *pnValue and moves the memory block behind the read data. |
78 | __checkReturn __success(return) inline BOOL GetU1(__out BYTE *pnValue); |
79 | __checkReturn __success(return) inline BOOL GetU2(__out UINT16 *pnValue); |
80 | __checkReturn __success(return) inline BOOL GetU4(__out UINT32 *pnValue); |
81 | __checkReturn __success(return) inline BOOL GetU8(__out UINT64 *pnValue); |
82 | |
83 | // Reads compressed integer (1, 2 or 4 bytes of format code:CompressedInteger#Format - returns the size |
84 | // in *pcbCompressedValueSize) from the data blob without skipping the read data. |
85 | // Returns FALSE if there's not enough data in the blob or the compression is invalid (starts with byte |
86 | // 111? ????), doesn't initialize the value *pnValue nor the size of the compressed value |
87 | // *pcbCompressedValueSize then. |
88 | // Returns TRUE otherwise, fills *pnValue and *pcbCompressedValueSize (with number 1,2 or 4), but |
89 | // doesn't move the memory block (doesn't skip the read data). |
90 | __checkReturn |
91 | __success(return) |
92 | inline BOOL PeekCompressedU( |
93 | __out UINT32 *pnValue, |
94 | __out UINT32 *pcbCompressedValueSize); |
95 | // Reads compressed integer (1, 2 or 4 bytes of format code:CompressedInteger#Format) from the data blob |
96 | // and skips the read data. |
97 | // Returns FALSE if there's not enough data in the blob or the compression is invalid (starts with byte |
98 | // 111? ????), doesn't initialize the value *pnValue then. |
99 | // Returns TRUE otherwise, fills *pnValue and moves the memory block behind the read data. |
100 | __checkReturn |
101 | __success(return) |
102 | inline BOOL GetCompressedU(__out UINT32 *pnValue); |
103 | // Reads compressed integer (1, 2 or 4 bytes of format code:CompressedInteger#Format - returns the size |
104 | // in *pcbCompressedValueSize) from the data blob and skips the read data. |
105 | // Returns FALSE if there's not enough data in the blob or the compression is invalid (starts with byte |
106 | // 111? ????), doesn't initialize the value *pnValue nor the size of the compressed value |
107 | // *pcbCompressedValueSize then. |
108 | // Returns TRUE otherwise, fills *pnValue and *pcbCompressedValueSize (with number 1,2 or 4) and moves |
109 | // the memory block behind the read data. |
110 | __checkReturn |
111 | __success(return) |
112 | inline BOOL GetCompressedU( |
113 | __out UINT32 *pnValue, |
114 | __out UINT32 *pcbCompressedValueSize); |
115 | |
116 | // Reads data of size cbDataSize and skips the data (instead of reading the bytes, returns the data as |
117 | // *pData). |
118 | // Returns FALSE if there's not enough data in the blob, clears *pData then. |
119 | // Returns TRUE otherwise, fills *pData with the "read" data and moves the memory block behind the |
120 | // "read" data. |
121 | __checkReturn |
122 | __success(return) |
123 | inline BOOL GetDataOfSize( |
124 | UINT32 cbDataSize, |
125 | __out DataBlob *pData); |
126 | |
127 | // Checks if there's at least cbDataSize bytes in the represented memory block. |
128 | // Returns TRUE if there's >= cbDataSize bytes. Returns FALSE otherwise. |
129 | inline BOOL ContainsData(UINT32 cbDataSize) const |
130 | { return cbDataSize <= m_cbSize; } |
131 | /* |
132 | // Checks if there's at least cbDataSize1 + cbDataSize2 bytes in the represented memory block (and that |
133 | // the sum doesn't overflow). |
134 | // Returns TRUE if there's >= cbDataSize1 + cbDataSize2 bytes. |
135 | // Returns FALSE otherwise and if cbDataSize1 + cbDataSize2 overflows. |
136 | inline BOOL ContainsData_2Parts( |
137 | UINT32 cbDataSize1, |
138 | UINT32 cbDataSize2) const; |
139 | // Checks if there's valid compressed integer (1, 2 or 4 bytes of format |
140 | // code:DataBlob#CompressedIntegerFormat) in the data blob. |
141 | // Returns: |
142 | // * 0 ... if there's valid compressed integer. |
143 | // * 1 ... if there's not enough data in the data blob, but the encoding is correct. |
144 | // * 2 ... if the integer encoding is invalid (starts with byte 111x xxxx byte), but there are at least |
145 | // 4 bytes in the data blob left. |
146 | // * 3 ... if there's not enough data in the data blob and the integer encoding is invalid (starts with |
147 | // 111x xxx byte). |
148 | inline int ValidateCompressedU() const; |
149 | */ |
150 | |
151 | // Returns TRUE if the represented memory is empty. |
152 | inline BOOL IsEmpty() const |
153 | { return (m_cbSize == 0); } |
154 | // Gets pointer to the represented data buffer (can be random pointer if size of the data is 0). |
155 | // Note: Should be used exceptionally. Try to use other operations instead. |
156 | inline BYTE *GetDataPointer() |
157 | { return m_pbData; } |
158 | // Gets pointer to the represented data buffer (can be random pointer if size of the data is 0). |
159 | // Note: Should be used exceptionally. Try to use other operations instead. |
160 | inline const BYTE *GetDataPointer() const |
161 | { return m_pbData; } |
162 | // Gets pointer right behind the represented data buffer (can be random pointer if size of the data is |
163 | // 0). |
164 | inline const BYTE *GetDataPointerBehind() const |
165 | { return ((m_cbSize == 0) ? NULL : (m_pbData + m_cbSize)); } |
166 | // Gets the size of represented memory. |
167 | inline UINT32 GetSize() const |
168 | { return m_cbSize; } |
169 | //BOOL SkipBytes(UINT32 cbSize); |
170 | |
171 | public: |
172 | // |
173 | // Operations |
174 | // |
175 | |
176 | // Truncates the buffer to exact size (cbSize). |
177 | // Returns FALSE if there's less than cbSize data represented. |
178 | // Returns TRUE otherwise and truncates the represented data size to cbSize. |
179 | __checkReturn |
180 | __success(return) |
181 | inline BOOL TruncateToExactSize(UINT32 cbSize); |
182 | // Truncates the buffer by size (cbSize). |
183 | // Returns FALSE if there's less than cbSize data represented. |
184 | // Returns TRUE otherwise and truncates the represented data size by cbSize. |
185 | __checkReturn |
186 | __success(return) |
187 | inline BOOL TruncateBySize(UINT32 cbSize); |
188 | |
189 | #ifdef _DEBUG |
190 | // Returns U1 value at offset (nOffset). Fires an assert if the offset is behind the end of represented |
191 | // data. |
192 | inline BYTE Debug_GetByteAtOffset(UINT32 nOffset) const; |
193 | #endif //_DEBUG |
194 | |
195 | public: |
196 | // |
197 | // Setters |
198 | // |
199 | |
200 | // Writes compressed integer (1, 2 or 4 bytes of format code:CompressedInteger#Format) to the data blob |
201 | // and skips the written data. |
202 | // Returns FALSE if there's not enough data in the blob or the value cannot be encoded as compressed |
203 | // integer (bigger than code:CompressedInteger::const_Max). |
204 | // Returns TRUE on success and moves the memory block behind the written data. |
205 | __checkReturn |
206 | __success(return) |
207 | inline BOOL StoreCompressedU(UINT32 nValue); |
208 | |
209 | // Writes data from *pSource to the data blob and skips the written data. |
210 | // Returns FALSE if there's not enough data in the blob. |
211 | // Returns TRUE on success and moves memory block behind the written data. |
212 | __checkReturn |
213 | __success(return) |
214 | inline BOOL StoreData(__in const DataBlob *pSource); |
215 | |
216 | private: |
217 | // |
218 | // Helpers |
219 | // |
220 | |
221 | // Skips cbSize bytes in the represented memory block. The caller is responsible for making sure that |
222 | // the represented memory block contains at least cbSize bytes, otherwise there will be a security |
223 | // issue. |
224 | // Should be used only internally, never call it from outside of this class. |
225 | inline void SkipBytes_InternalInsecure(UINT32 cbSize); |
226 | |
227 | }; // class DataBlob |
228 | |
229 | }; // namespace MetaData |
230 | |
231 | #include "datablob.inl" |
232 | |