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 | |
19 | int 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 | |
36 | int 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 | |
69 | int 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 | //***************************************************************************** |
92 | void 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 | //***************************************************************************** |
130 | HRESULT 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 | //***************************************************************************** |
196 | HRESULT 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 | //***************************************************************************** |
232 | HRESULT 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 | //***************************************************************************** |
247 | ULONG 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 | //***************************************************************************** |
280 | ULONG 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 |
316 | void* 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 | |