summaryrefslogtreecommitdiff
path: root/src/md/datablob.h
blob: 8e00b29cfeeba320d7e553da4edd424931cc1958 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license 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"