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// StgPool.cpp
6//
7
8//
9// Pools are used to reduce the amount of data actually required in the database.
10// This allows for duplicate string and binary values to be folded into one
11// copy shared by the rest of the database. Strings are tracked in a hash
12// table when insert/changing data to find duplicates quickly. The strings
13// are then persisted consecutively in a stream in the database format.
14//
15//*****************************************************************************
16#include "stdafx.h" // Standard include.
17#include <stgpool.h> // Our interface definitions.
18
19int CStringPoolHash::Cmp(
20 const void *pData, // A string.
21 void *pItem) // A hash item which refers to a string.
22{
23 STATIC_CONTRACT_NOTHROW;
24 STATIC_CONTRACT_FORBID_FAULT;
25
26 LPCSTR p1 = reinterpret_cast<LPCSTR>(pData);
27 LPCSTR p2;
28 if (FAILED(m_Pool->GetString(reinterpret_cast<STRINGHASH*>(pItem)->iOffset, &p2)))
29 {
30 return -1;
31 }
32 return (strcmp(p1, p2));
33} // int CStringPoolHash::Cmp()
34
35
36int CBlobPoolHash::Cmp(
37 const void *pData, // A blob.
38 void *pItem) // A hash item which refers to a blob.
39{
40 STATIC_CONTRACT_NOTHROW;
41 STATIC_CONTRACT_FORBID_FAULT;
42
43 ULONG ul1;
44 ULONG ul2;
45 MetaData::DataBlob data2;
46
47 // Get size of first item.
48 ul1 = CPackedLen::GetLength(pData);
49 // Adjust size to include the length of size field.
50 ul1 += CPackedLen::Size(ul1);
51
52 // Get the second item.
53 if (FAILED(m_Pool->GetData(reinterpret_cast<BLOBHASH*>(pItem)->iOffset, &data2)))
54 {
55 return -1;
56 }
57
58 // Get and adjust size of second item.
59 ul2 = CPackedLen::GetLength(data2.GetDataPointer());
60 ul2 += CPackedLen::Size(ul2);
61
62 if (ul1 < ul2)
63 return (-1);
64 else if (ul1 > ul2)
65 return (1);
66 return (memcmp(pData, data2.GetDataPointer(), ul1));
67} // int CBlobPoolHash::Cmp()
68
69int CGuidPoolHash::Cmp(const void *pData, void *pItem)
70{
71 STATIC_CONTRACT_NOTHROW;
72 STATIC_CONTRACT_FORBID_FAULT;
73
74 GUID *p2;
75 if (FAILED(m_Pool->GetGuid(reinterpret_cast<GUIDHASH*>(pItem)->iIndex, &p2)))
76 {
77 return -1;
78 }
79 return (memcmp(pData, p2, sizeof(GUID)));
80} // int CGuidPoolHash::Cmp()
81
82//
83//
84// CPackedLen
85//
86//
87
88
89//*****************************************************************************
90// Parse a length, return the data, store length.
91//*****************************************************************************
92void const *CPackedLen::GetData( // Pointer to data, or 0 on error.
93 void const *pData, // First byte of length.
94 ULONG *pLength) // Put length here, or -1 on error.
95{
96 STATIC_CONTRACT_NOTHROW;
97 STATIC_CONTRACT_FORBID_FAULT;
98
99 BYTE const *pBytes = reinterpret_cast<BYTE const*>(pData);
100
101 if ((*pBytes & 0x80) == 0x00) // 0??? ????
102 {
103 *pLength = (*pBytes & 0x7f);
104 return pBytes + 1;
105 }
106
107 if ((*pBytes & 0xC0) == 0x80) // 10?? ????
108 {
109 *pLength = ((*pBytes & 0x3f) << 8 | *(pBytes+1));
110 return pBytes + 2;
111 }
112
113 if ((*pBytes & 0xE0) == 0xC0) // 110? ????
114 {
115 *pLength = ((*pBytes & 0x1f) << 24 | *(pBytes+1) << 16 | *(pBytes+2) << 8 | *(pBytes+3));
116 return pBytes + 4;
117 }
118
119 *pLength = (ULONG) -1;
120 return 0;
121} // void const *CPackedLen::GetData()
122
123#ifndef MAX_PTR
124#define MAX_PTR ((BYTE*)(~(SSIZE_T)0))
125#endif
126
127//*****************************************************************************
128// Parse a length, return the data, store length.
129//*****************************************************************************
130HRESULT CPackedLen::SafeGetLength( // S_OK, or error
131 void const *pDataSource, // First byte of length.
132 void const *pDataSourceEnd, // End of valid source data memory
133 ULONG *pLength, // Length of data, if return S_OK
134 void const **ppDataNext) // Pointer immediately following encoded length
135{
136 STATIC_CONTRACT_NOTHROW;
137 STATIC_CONTRACT_FORBID_FAULT;
138
139 if (pDataSource == NULL ||
140 pDataSourceEnd == NULL ||
141 pDataSourceEnd < pDataSource ||
142 ppDataNext == NULL ||
143 pLength == NULL ||
144 pDataSource > (MAX_PTR - 4))
145 {
146 return E_INVALIDARG;
147 }
148
149 BYTE const *pBytes = reinterpret_cast<BYTE const*>(pDataSource);
150 BYTE const *pBytesEnd = reinterpret_cast<BYTE const*>(pDataSourceEnd);
151
152 size_t cbAvail = pBytesEnd - pBytes;
153
154 if (cbAvail < 1)
155 { // Fail if no source data available
156 return COR_E_OVERFLOW;
157 }
158
159 if ((*pBytes & 0x80) == 0x00) // 0??? ????
160 {
161 *pLength = (*pBytes & 0x7f);
162 *ppDataNext = pBytes + 1;
163 return S_OK;
164 }
165
166 if (cbAvail < 2)
167 { // Fail if not enough source data available
168 return COR_E_OVERFLOW;
169 }
170
171 if ((*pBytes & 0xC0) == 0x80) // 10?? ????
172 {
173 *pLength = ((*pBytes & 0x3f) << 8 | *(pBytes+1));
174 *ppDataNext = pBytes + 2;
175 return S_OK;
176 }
177
178 if (cbAvail < 4)
179 { // Fail if not enough source data available
180 return COR_E_OVERFLOW;
181 }
182
183 if ((*pBytes & 0xE0) == 0xC0) // 110? ????
184 {
185 *pLength = ((*pBytes & 0x1f) << 24 | *(pBytes+1) << 16 | *(pBytes+2) << 8 | *(pBytes+3));
186 *ppDataNext = pBytes + 4;
187 return S_OK;;
188 }
189
190 return COR_E_OVERFLOW;
191} // CPackedLen::GetLength
192
193//*****************************************************************************
194// Parse a length, return the data, store length.
195//*****************************************************************************
196HRESULT CPackedLen::SafeGetData( // S_OK, or error
197 void const *pDataSource, // First byte of length.
198 void const *pDataSourceEnd, // End of valid source data memory
199 ULONG *pcbData, // Length of data
200 void const **ppData) // Start of data
201{
202 STATIC_CONTRACT_NOTHROW;
203 STATIC_CONTRACT_FORBID_FAULT;
204
205 HRESULT hr = S_OK;
206
207 IfFailRet(SafeGetLength(pDataSource, pDataSourceEnd, pcbData, ppData));
208
209 if (*pcbData == 0)
210 { // Zero length value means zero data, so no range checking required.
211 return S_OK;
212 }
213
214 BYTE const *pbData = reinterpret_cast<BYTE const*>(*ppData);
215
216 if (pbData + *pcbData < pbData)
217 { // First check for integer overflow
218 return COR_E_OVERFLOW;
219 }
220
221 if (pDataSourceEnd < pbData + *pcbData)
222 { // Now check for data buffer overflow
223 return COR_E_OVERFLOW;
224 }
225
226 return S_OK;
227} // CPackedLen::GetLength
228
229//*****************************************************************************
230// Parse a length, return the data, store length.
231//*****************************************************************************
232HRESULT CPackedLen::SafeGetData( // S_OK, or error
233 void const *pDataSource, // First byte of data
234 ULONG cbDataSource, // Count of valid bytes in data source
235 ULONG *pcbData, // Length of data
236 void const **ppData) // Start of data
237{
238 STATIC_CONTRACT_NOTHROW;
239 STATIC_CONTRACT_FORBID_FAULT;
240
241 return SafeGetData(pDataSource, (void const *)((BYTE const *)pDataSource + cbDataSource), pcbData, ppData);
242} // CPackedLen::GetLength
243
244//*****************************************************************************
245// Parse a length, return the length, pointer to actual bytes.
246//*****************************************************************************
247ULONG CPackedLen::GetLength( // Length or -1 on error.
248 void const *pData, // First byte of length.
249 void const **ppCode) // Put pointer to bytes here, if not 0.
250{
251 STATIC_CONTRACT_NOTHROW;
252 STATIC_CONTRACT_FORBID_FAULT;
253
254 BYTE const *pBytes = reinterpret_cast<BYTE const*>(pData);
255
256 if ((*pBytes & 0x80) == 0x00) // 0??? ????
257 {
258 if (ppCode) *ppCode = pBytes + 1;
259 return (*pBytes & 0x7f);
260 }
261
262 if ((*pBytes & 0xC0) == 0x80) // 10?? ????
263 {
264 if (ppCode) *ppCode = pBytes + 2;
265 return ((*pBytes & 0x3f) << 8 | *(pBytes+1));
266 }
267
268 if ((*pBytes & 0xE0) == 0xC0) // 110? ????
269 {
270 if (ppCode) *ppCode = pBytes + 4;
271 return ((*pBytes & 0x1f) << 24 | *(pBytes+1) << 16 | *(pBytes+2) << 8 | *(pBytes+3));
272 }
273
274 return (ULONG) -1;
275} // ULONG CPackedLen::GetLength()
276
277//*****************************************************************************
278// Parse a length, return the length, size of the length.
279//*****************************************************************************
280ULONG CPackedLen::GetLength( // Length or -1 on error.
281 void const *pData, // First byte of length.
282 int *pSizeLen) // Put size of length here, if not 0.
283{
284 STATIC_CONTRACT_NOTHROW;
285 STATIC_CONTRACT_FORBID_FAULT;
286
287 BYTE const *pBytes = reinterpret_cast<BYTE const*>(pData);
288
289 if ((*pBytes & 0x80) == 0x00) // 0??? ????
290 {
291 if (pSizeLen) *pSizeLen = 1;
292 return (*pBytes & 0x7f);
293 }
294
295 if ((*pBytes & 0xC0) == 0x80) // 10?? ????
296 {
297 if (pSizeLen) *pSizeLen = 2;
298 return ((*pBytes & 0x3f) << 8 | *(pBytes+1));
299 }
300
301 if ((*pBytes & 0xE0) == 0xC0) // 110? ????
302 {
303 if (pSizeLen) *pSizeLen = 4;
304 return ((*pBytes & 0x1f) << 24 | *(pBytes+1) << 16 | *(pBytes+2) << 8 | *(pBytes+3));
305 }
306
307 return (ULONG) -1;
308} // ULONG CPackedLen::GetLength()
309
310//*****************************************************************************
311// Encode a length.
312//*****************************************************************************
313#ifdef _MSC_VER
314#pragma warning(disable:4244) // conversion from unsigned long to unsigned char
315#endif
316void* CPackedLen::PutLength( // First byte past length.
317 void *pData, // Pack the length here.
318 ULONG iLen) // The length.
319{
320 STATIC_CONTRACT_NOTHROW;
321 STATIC_CONTRACT_FORBID_FAULT;
322
323 BYTE *pBytes = reinterpret_cast<BYTE*>(pData);
324
325 if (iLen <= 0x7F)
326 {
327 *pBytes = iLen;
328 return pBytes + 1;
329 }
330
331 if (iLen <= 0x3FFF)
332 {
333 *pBytes = (iLen >> 8) | 0x80;
334 *(pBytes+1) = iLen & 0xFF;
335 return pBytes + 2;
336 }
337
338 _ASSERTE(iLen <= 0x1FFFFFFF);
339 *pBytes = (iLen >> 24) | 0xC0;
340 *(pBytes+1) = (iLen >> 16) & 0xFF;
341 *(pBytes+2) = (iLen >> 8) & 0xFF;
342 *(pBytes+3) = iLen & 0xFF;
343 return pBytes + 4;
344} // void* CPackedLen::PutLength()
345#ifdef _MSC_VER
346#pragma warning(default:4244) // conversion from unsigned long to unsigned char
347#endif
348
349