| 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: RegMeta_IMetaDataTables.cpp | 
|---|
| 6 | // | 
|---|
| 7 |  | 
|---|
| 8 | // | 
|---|
| 9 | // Methods of code:RegMeta class which implement public API interfaces code:IMetaDataTables: | 
|---|
| 10 | //  * code:RegMeta::GetStringHeapSize | 
|---|
| 11 | //  * code:RegMeta::GetBlobHeapSize | 
|---|
| 12 | //  * code:RegMeta::GetGuidHeapSize | 
|---|
| 13 | //  * code:RegMeta::GetUserStringHeapSize | 
|---|
| 14 | // | 
|---|
| 15 | //  * code:RegMeta#GetString_IMetaDataTables | 
|---|
| 16 | //  * code:RegMeta#GetBlob_IMetaDataTables | 
|---|
| 17 | //  * code:RegMeta#GetGuid_IMetaDataTables | 
|---|
| 18 | //  * code:RegMeta#GetUserString_IMetaDataTables | 
|---|
| 19 | // | 
|---|
| 20 | //  * code:RegMeta::GetNextString | 
|---|
| 21 | //  * code:RegMeta::GetNextBlob | 
|---|
| 22 | //  * code:RegMeta::GetNextGuid | 
|---|
| 23 | //  * code:RegMeta::GetNextUserString | 
|---|
| 24 | // | 
|---|
| 25 | //  * code:RegMeta::GetNumTables | 
|---|
| 26 | //  * code:RegMeta::GetTableIndex | 
|---|
| 27 | //  * code:RegMeta::GetTableInfo | 
|---|
| 28 | //  * code:RegMeta::GetColumnInfo | 
|---|
| 29 | //  * code:RegMeta::GetCodedTokenInfo | 
|---|
| 30 | //  * code:RegMeta::GetRow | 
|---|
| 31 | //  * code:RegMeta::GetColumn | 
|---|
| 32 | // | 
|---|
| 33 | // Methods of code:RegMeta class which implement public API interfaces code:IMetaDataTables2: | 
|---|
| 34 | //  * code:RegMeta::GetMetaDataStorage | 
|---|
| 35 | //  * code:RegMeta::GetMetaDataStreamInfo | 
|---|
| 36 | // | 
|---|
| 37 | // ====================================================================================== | 
|---|
| 38 |  | 
|---|
| 39 | #include "stdafx.h" | 
|---|
| 40 | #include "regmeta.h" | 
|---|
| 41 |  | 
|---|
| 42 | // -------------------------------------------------------------------------------------- | 
|---|
| 43 | // | 
|---|
| 44 | // Fills size (*pcbStringsHeapSize) of internal strings heap (#String). | 
|---|
| 45 | // Returns S_OK or error code. Fills *pcbStringsHeapSize with 0 on error. | 
|---|
| 46 | // Implements public API code:IMetaDataTables::GetStringHeapSize. | 
|---|
| 47 | // | 
|---|
| 48 | HRESULT | 
|---|
| 49 | RegMeta::GetStringHeapSize( | 
|---|
| 50 | __out ULONG *pcbStringsHeapSize)    // [OUT] Size of the string heap. | 
|---|
| 51 | { | 
|---|
| 52 | HRESULT hr = S_OK; | 
|---|
| 53 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 54 |  | 
|---|
| 55 | *pcbStringsHeapSize = m_pStgdb->m_MiniMd.m_StringHeap.GetUnalignedSize(); | 
|---|
| 56 |  | 
|---|
| 57 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 58 | return hr; | 
|---|
| 59 | } // RegMeta::GetStringHeapSize | 
|---|
| 60 |  | 
|---|
| 61 | // -------------------------------------------------------------------------------------- | 
|---|
| 62 | // | 
|---|
| 63 | // Fills size (*pcbBlobsHeapSize) of blobs heap (#Blob). | 
|---|
| 64 | // Returns S_OK or error code. Fills *pcbBlobsHeapSize with 0 on error. | 
|---|
| 65 | // Implements public API code:IMetaDataTables::GetBlobHeapSize. | 
|---|
| 66 | // | 
|---|
| 67 | HRESULT | 
|---|
| 68 | RegMeta::GetBlobHeapSize( | 
|---|
| 69 | __out ULONG *pcbBlobsHeapSize)  // [OUT] Size of the blob heap. | 
|---|
| 70 | { | 
|---|
| 71 | HRESULT hr = S_OK; | 
|---|
| 72 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 73 |  | 
|---|
| 74 | *pcbBlobsHeapSize = m_pStgdb->m_MiniMd.m_BlobHeap.GetUnalignedSize(); | 
|---|
| 75 |  | 
|---|
| 76 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 77 | return hr; | 
|---|
| 78 | } // RegMeta::GetBlobHeapSize | 
|---|
| 79 |  | 
|---|
| 80 | // -------------------------------------------------------------------------------------- | 
|---|
| 81 | // | 
|---|
| 82 | // Fills size (*pcbGuidsHeapSize) of guids heap (#GUID). | 
|---|
| 83 | // Returns S_OK or error code. Fills *pcbGuidsHeapSize with 0 on error. | 
|---|
| 84 | // Implements public API code:IMetaDataTables::GetGuidHeapSize. | 
|---|
| 85 | // | 
|---|
| 86 | HRESULT | 
|---|
| 87 | RegMeta::GetGuidHeapSize( | 
|---|
| 88 | __out ULONG *pcbGuidsHeapSize)      // [OUT] Size of the Guid heap. | 
|---|
| 89 | { | 
|---|
| 90 | HRESULT hr = S_OK; | 
|---|
| 91 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 92 |  | 
|---|
| 93 | *pcbGuidsHeapSize = m_pStgdb->m_MiniMd.m_GuidHeap.GetSize(); | 
|---|
| 94 |  | 
|---|
| 95 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 96 | return hr; | 
|---|
| 97 | } // RegMeta::GetGuidHeapSize | 
|---|
| 98 |  | 
|---|
| 99 | // -------------------------------------------------------------------------------------- | 
|---|
| 100 | // | 
|---|
| 101 | // Fills size (*pcbUserStringsHeapSize) of user strings heap (#US) (referenced from IL). | 
|---|
| 102 | // Returns S_OK or error code. Fills *pcbUserStringsHeapSize with 0 on error. | 
|---|
| 103 | // Implements public API code:IMetaDataTables::GetUserStringHeapSize. | 
|---|
| 104 | // | 
|---|
| 105 | HRESULT | 
|---|
| 106 | RegMeta::GetUserStringHeapSize( | 
|---|
| 107 | __out ULONG *pcbUserStringsHeapSize)    // [OUT] Size of the user string heap. | 
|---|
| 108 | { | 
|---|
| 109 | HRESULT hr = S_OK; | 
|---|
| 110 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 111 |  | 
|---|
| 112 | *pcbUserStringsHeapSize = m_pStgdb->m_MiniMd.m_UserStringHeap.GetUnalignedSize(); | 
|---|
| 113 |  | 
|---|
| 114 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 115 | return hr; | 
|---|
| 116 | } // RegMeta::GetUserStringHeapSize | 
|---|
| 117 |  | 
|---|
| 118 | // -------------------------------------------------------------------------------------- | 
|---|
| 119 | // | 
|---|
| 120 | //#GetString_IMetaDataTables | 
|---|
| 121 | // | 
|---|
| 122 | // Fills internal null-terminated string (*pszString) at index ixString from string heap (#String). | 
|---|
| 123 | // Returns S_OK (even for index 0) or error code (if index is invalid, fills *pszString with NULL then). | 
|---|
| 124 | // Implements public API code:IMetaDataTables::GetString. | 
|---|
| 125 | // | 
|---|
| 126 | HRESULT RegMeta::GetString( | 
|---|
| 127 | ULONG        ixString,      // [IN] Value from a string column. | 
|---|
| 128 | const char **pszString)     // [OUT] Put a pointer to the string here. | 
|---|
| 129 | { | 
|---|
| 130 | HRESULT hr = S_OK; | 
|---|
| 131 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 132 |  | 
|---|
| 133 | IfFailGo(m_pStgdb->m_MiniMd.getString( | 
|---|
| 134 | ixString, | 
|---|
| 135 | pszString)); | 
|---|
| 136 |  | 
|---|
| 137 | _ASSERTE(hr == S_OK); | 
|---|
| 138 | goto Exit; | 
|---|
| 139 | ErrExit: | 
|---|
| 140 | *pszString = NULL; | 
|---|
| 141 | Exit: | 
|---|
| 142 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 143 | return hr; | 
|---|
| 144 | } // RegMeta::GetString | 
|---|
| 145 |  | 
|---|
| 146 | // -------------------------------------------------------------------------------------- | 
|---|
| 147 | // | 
|---|
| 148 | //#GetBlob_IMetaDataTables | 
|---|
| 149 | // | 
|---|
| 150 | // Fills blob entry (*ppvData of size *pcbDataSize) at index ixBlob from blob heap (#Blob). | 
|---|
| 151 | // Returns S_OK (even for index 0) or error code (if index is invalid, fills NULL and o then). | 
|---|
| 152 | // Implements public API code:IMetaDataTables::GetBlob. | 
|---|
| 153 | // | 
|---|
| 154 | HRESULT RegMeta::GetBlob( | 
|---|
| 155 | ULONG        ixBlob,        // [IN] Value from a blob column. | 
|---|
| 156 | __out       ULONG       *pcbDataSize,   // [OUT] Put size of the blob here. | 
|---|
| 157 | __deref_out const void **ppvData)       // [OUT] Put a pointer to the blob here. | 
|---|
| 158 | { | 
|---|
| 159 | HRESULT hr = S_OK; | 
|---|
| 160 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 161 |  | 
|---|
| 162 | MetaData::DataBlob dataBlob; | 
|---|
| 163 | IfFailGo(m_pStgdb->m_MiniMd.getBlob(ixBlob, &dataBlob)); | 
|---|
| 164 |  | 
|---|
| 165 | *ppvData = (const void *)dataBlob.GetDataPointer(); | 
|---|
| 166 | *pcbDataSize = dataBlob.GetSize(); | 
|---|
| 167 |  | 
|---|
| 168 | _ASSERTE(hr == S_OK); | 
|---|
| 169 | goto Exit; | 
|---|
| 170 | ErrExit: | 
|---|
| 171 | *ppvData = NULL; | 
|---|
| 172 | *pcbDataSize = 0; | 
|---|
| 173 | Exit: | 
|---|
| 174 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 175 | return hr; | 
|---|
| 176 | } // RegMeta::GetBlob | 
|---|
| 177 |  | 
|---|
| 178 | // -------------------------------------------------------------------------------------- | 
|---|
| 179 | // | 
|---|
| 180 | //#GetGuid_IMetaDataTables | 
|---|
| 181 | // | 
|---|
| 182 | // Fills guid (*ppGuid) at index ixGuid from guid heap (#GUID). | 
|---|
| 183 | // Returns S_OK and fills *ppGuid. Returns S_OK even for (invalid) index 0 (fills *ppGuid with pointer to | 
|---|
| 184 | // zeros then). | 
|---|
| 185 | // Retruns error code (if index is invalid except 0, fills NULL and o then). | 
|---|
| 186 | // Implements public API code:IMetaDataTables::GetGuid. | 
|---|
| 187 | // | 
|---|
| 188 | // Backward compatibility: returns S_OK even if the index is 0 which is invalid as specified in CLI ECMA | 
|---|
| 189 | // specification. In that case returns pointer to GUID from zeros. | 
|---|
| 190 | // | 
|---|
| 191 | HRESULT RegMeta::GetGuid( | 
|---|
| 192 | ULONG        ixGuid,    // [IN] Value from a guid column. | 
|---|
| 193 | const GUID **ppGuid)    // [OUT] Put a pointer to the GUID here. | 
|---|
| 194 | { | 
|---|
| 195 | HRESULT hr = S_OK; | 
|---|
| 196 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 197 |  | 
|---|
| 198 | REGMETA_POSSIBLE_INTERNAL_POINTER_EXPOSED(); | 
|---|
| 199 |  | 
|---|
| 200 | if (ixGuid == 0) | 
|---|
| 201 | { | 
|---|
| 202 | // Return zeros | 
|---|
| 203 | *ppGuid = GetPublicApiCompatibilityZeros<const GUID>(); | 
|---|
| 204 | hr = S_OK; | 
|---|
| 205 | } | 
|---|
| 206 | else | 
|---|
| 207 | { | 
|---|
| 208 | IfFailGo(m_pStgdb->m_MiniMd.m_GuidHeap.GetGuid( | 
|---|
| 209 | ixGuid, | 
|---|
| 210 | ppGuid)); | 
|---|
| 211 | } | 
|---|
| 212 |  | 
|---|
| 213 | ErrExit: | 
|---|
| 214 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 215 | return hr; | 
|---|
| 216 | } // RegMeta::GetGuid | 
|---|
| 217 |  | 
|---|
| 218 | // -------------------------------------------------------------------------------------- | 
|---|
| 219 | // | 
|---|
| 220 | //#GetUserString_IMetaDataTables | 
|---|
| 221 | // | 
|---|
| 222 | // Fills user string (*ppvData of size *pcbDataSize) at index ixUserString. | 
|---|
| 223 | // Returns S_OK (even for index 0) or error code (if index is invalid, fills NULL and o then). | 
|---|
| 224 | // Implements public API code:IMetaDataTables::GetUserString. | 
|---|
| 225 | // | 
|---|
| 226 | HRESULT | 
|---|
| 227 | RegMeta::GetUserString( | 
|---|
| 228 | ULONG        ixUserString,      // [IN] Value from a UserString column. | 
|---|
| 229 | __out           ULONG       *pcbDataSize,       // [OUT] Put size of the UserString here. | 
|---|
| 230 | __deref_out_opt const void **ppvData)           // [OUT] Put a pointer to the UserString here. | 
|---|
| 231 | { | 
|---|
| 232 | HRESULT hr = S_OK; | 
|---|
| 233 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 234 |  | 
|---|
| 235 | MetaData::DataBlob userString; | 
|---|
| 236 | IfFailGo(m_pStgdb->m_MiniMd.GetUserString(ixUserString, &userString)); | 
|---|
| 237 | _ASSERTE(hr == S_OK); | 
|---|
| 238 |  | 
|---|
| 239 | *ppvData = (const void *)userString.GetDataPointer(); | 
|---|
| 240 | *pcbDataSize = userString.GetSize(); | 
|---|
| 241 |  | 
|---|
| 242 | goto Exit; | 
|---|
| 243 | ErrExit: | 
|---|
| 244 | *ppvData = NULL; | 
|---|
| 245 | *pcbDataSize = 0; | 
|---|
| 246 | Exit: | 
|---|
| 247 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 248 | return hr; | 
|---|
| 249 | } // RegMeta::GetUserString | 
|---|
| 250 |  | 
|---|
| 251 | // -------------------------------------------------------------------------------------- | 
|---|
| 252 | // | 
|---|
| 253 | //#GetNextString_IMetaDataTables | 
|---|
| 254 | // | 
|---|
| 255 | // Fills index of string (*pixNextString) from the internal strings heap (#String) starting behind string | 
|---|
| 256 | // at index ixString. | 
|---|
| 257 | // Returns S_OK or S_FALSE (if either index is invalid). Fills *pixNextString with 0 on S_FALSE. | 
|---|
| 258 | // Implements public API code:IMetaDataTables::GetNextString. | 
|---|
| 259 | // | 
|---|
| 260 | HRESULT | 
|---|
| 261 | RegMeta::GetNextString( | 
|---|
| 262 | ULONG  ixString,        // [IN] Value from a string column. | 
|---|
| 263 | __out ULONG *pixNextString)   // [OUT] Put the index of the next string here. | 
|---|
| 264 | { | 
|---|
| 265 | HRESULT hr = S_OK; | 
|---|
| 266 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 267 |  | 
|---|
| 268 | REGMETA_POSSIBLE_INTERNAL_POINTER_EXPOSED(); | 
|---|
| 269 |  | 
|---|
| 270 | // Get string at index ixString | 
|---|
| 271 | LPCSTR szString; | 
|---|
| 272 | IfFailGo(m_pStgdb->m_MiniMd.m_StringHeap.GetString( | 
|---|
| 273 | ixString, | 
|---|
| 274 | &szString)); | 
|---|
| 275 | _ASSERTE(hr == S_OK); | 
|---|
| 276 |  | 
|---|
| 277 | // Get index behind the string - doesn't overflow, because string heap was verified | 
|---|
| 278 | UINT32 ixNextString; | 
|---|
| 279 | ixNextString = ixString + (UINT32)(strlen(szString) + 1); | 
|---|
| 280 |  | 
|---|
| 281 | // Verify that the next index is in the string heap | 
|---|
| 282 | if (!m_pStgdb->m_MiniMd.m_StringHeap.IsValidIndex(ixNextString)) | 
|---|
| 283 | {   // The next index is invalid | 
|---|
| 284 | goto ErrExit; | 
|---|
| 285 | } | 
|---|
| 286 | // The next index is valid | 
|---|
| 287 | *pixNextString = ixNextString; | 
|---|
| 288 | goto Exit; | 
|---|
| 289 |  | 
|---|
| 290 | ErrExit: | 
|---|
| 291 | // Fill output parameters on error | 
|---|
| 292 | *pixNextString = 0; | 
|---|
| 293 | // Return S_FALSE if either of the string indexes is invalid (backward API compatibility) | 
|---|
| 294 | hr = S_FALSE; | 
|---|
| 295 | Exit: | 
|---|
| 296 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 297 | return hr; | 
|---|
| 298 | } // RegMeta::GetNextString | 
|---|
| 299 |  | 
|---|
| 300 | // -------------------------------------------------------------------------------------- | 
|---|
| 301 | // | 
|---|
| 302 | //#GetNextBlob_IMetaDataTables | 
|---|
| 303 | // | 
|---|
| 304 | // Fills index of blob (*pixNextBlob) from the blobs heap (#Blob) starting behind blob at index ixBlob. | 
|---|
| 305 | // Returns S_OK or S_FALSE (if either index is invalid). Fills *pixNextBlob with 0 on S_FALSE. | 
|---|
| 306 | // Implements public API code:IMetaDataTables::GetNextString. | 
|---|
| 307 | // | 
|---|
| 308 | HRESULT | 
|---|
| 309 | RegMeta::GetNextBlob( | 
|---|
| 310 | ULONG  ixBlob,        // [IN] Value from a blob column. | 
|---|
| 311 | __out ULONG *pixNextBlob)   // [OUT] Put the index of the next blob here. | 
|---|
| 312 | { | 
|---|
| 313 | HRESULT hr = S_OK; | 
|---|
| 314 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 315 |  | 
|---|
| 316 | REGMETA_POSSIBLE_INTERNAL_POINTER_EXPOSED(); | 
|---|
| 317 |  | 
|---|
| 318 | // Get blob at index ixBlob (verifies that the blob is in the blob heap) | 
|---|
| 319 | MetaData::DataBlob blob; | 
|---|
| 320 | IfFailGo(m_pStgdb->m_MiniMd.m_BlobHeap.GetBlobWithSizePrefix( | 
|---|
| 321 | ixBlob, | 
|---|
| 322 | &blob)); | 
|---|
| 323 | _ASSERTE(hr == S_OK); | 
|---|
| 324 |  | 
|---|
| 325 | // Get index behind the blob - doesn't overflow, because the blob is in the blob heap | 
|---|
| 326 | UINT32 ixNextBlob; | 
|---|
| 327 | ixNextBlob = ixBlob + blob.GetSize(); | 
|---|
| 328 |  | 
|---|
| 329 | // Verify that the next index is in the blob heap | 
|---|
| 330 | if (!m_pStgdb->m_MiniMd.m_BlobHeap.IsValidIndex(ixNextBlob)) | 
|---|
| 331 | {   // The next index is invalid | 
|---|
| 332 | goto ErrExit; | 
|---|
| 333 | } | 
|---|
| 334 | // The next index is valid | 
|---|
| 335 | *pixNextBlob = ixNextBlob; | 
|---|
| 336 | goto Exit; | 
|---|
| 337 |  | 
|---|
| 338 | ErrExit: | 
|---|
| 339 | // Fill output parameters on error | 
|---|
| 340 | *pixNextBlob = 0; | 
|---|
| 341 | // Return S_FALSE if either of the string indexes is invalid (backward API compatibility) | 
|---|
| 342 | hr = S_FALSE; | 
|---|
| 343 | Exit: | 
|---|
| 344 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 345 | return hr; | 
|---|
| 346 | } // RegMeta::GetNextBlob | 
|---|
| 347 |  | 
|---|
| 348 | // -------------------------------------------------------------------------------------- | 
|---|
| 349 | // | 
|---|
| 350 | //#GetNextGuid_IMetaDataTables | 
|---|
| 351 | // | 
|---|
| 352 | // Fills index of guid (*pixNextGuid) from the guids heap (#GUID) starting behind guid at index ixGuid. | 
|---|
| 353 | // Returns S_OK or S_FALSE (if the new index is invalid). Fills *pixNextGuid with 0 on S_FALSE. | 
|---|
| 354 | // Implements public API code:IMetaDataTables::GetNextGuid. | 
|---|
| 355 | // | 
|---|
| 356 | // Backward compatibility: returns S_OK even if the guid index (ixGuid) is 0 which is invalid as | 
|---|
| 357 | // specified in CLI ECMA specification. | 
|---|
| 358 | // | 
|---|
| 359 | HRESULT | 
|---|
| 360 | RegMeta::GetNextGuid( | 
|---|
| 361 | ULONG  ixGuid,            // [IN] Value from a guid column. | 
|---|
| 362 | __out ULONG *pixNextGuid)       // [OUT] Put the index of the next guid here. | 
|---|
| 363 | { | 
|---|
| 364 | HRESULT hr = S_OK; | 
|---|
| 365 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 366 |  | 
|---|
| 367 | S_UINT32 ixNextGuid = S_UINT32(ixGuid) + S_UINT32(1); | 
|---|
| 368 | if (ixNextGuid.IsOverflow()) | 
|---|
| 369 | {   // It's invalid index (UINT32_MAX) | 
|---|
| 370 | goto ErrExit; | 
|---|
| 371 | } | 
|---|
| 372 | if (!m_pStgdb->m_MiniMd.m_GuidHeap.IsValidIndex(ixNextGuid.Value())) | 
|---|
| 373 | {   // The next index is invalid | 
|---|
| 374 | goto ErrExit; | 
|---|
| 375 | } | 
|---|
| 376 | _ASSERTE(hr == S_OK); | 
|---|
| 377 | // The next index is valid | 
|---|
| 378 | *pixNextGuid = ixNextGuid.Value(); | 
|---|
| 379 | goto Exit; | 
|---|
| 380 |  | 
|---|
| 381 | ErrExit: | 
|---|
| 382 | // Fill output parameters on error | 
|---|
| 383 | *pixNextGuid = 0; | 
|---|
| 384 | // Return S_FALSE if next guid index is invalid (backward API compatibility) | 
|---|
| 385 | hr = S_FALSE; | 
|---|
| 386 | Exit: | 
|---|
| 387 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 388 | return hr; | 
|---|
| 389 | } // RegMeta::GetNextGuid | 
|---|
| 390 |  | 
|---|
| 391 | // -------------------------------------------------------------------------------------- | 
|---|
| 392 | // | 
|---|
| 393 | //#GetNextUserString_IMetaDataTables | 
|---|
| 394 | // | 
|---|
| 395 | // Fills index of user string (*pixNextUserString) from the user strings heap (#US) starting behind string | 
|---|
| 396 | // at index ixUserString. | 
|---|
| 397 | // Returns S_OK or S_FALSE (if either index is invalid). Fills *pixNextUserString with 0 on S_FALSE. | 
|---|
| 398 | // Implements public API code:IMetaDataTables::GetNextUserString. | 
|---|
| 399 | // | 
|---|
| 400 | // Backward compatibility: returns S_OK even if the string doesn't have odd number of bytes as specified | 
|---|
| 401 | // in CLI ECMA specification. | 
|---|
| 402 | // | 
|---|
| 403 | HRESULT | 
|---|
| 404 | RegMeta::GetNextUserString( | 
|---|
| 405 | ULONG  ixUserString,          // [IN] Value from a UserString column. | 
|---|
| 406 | __out ULONG *pixNextUserString)     // [OUT] Put the index of the next user string here. | 
|---|
| 407 | { | 
|---|
| 408 | HRESULT hr = S_OK; | 
|---|
| 409 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 410 |  | 
|---|
| 411 | REGMETA_POSSIBLE_INTERNAL_POINTER_EXPOSED(); | 
|---|
| 412 |  | 
|---|
| 413 | // Get user string at index ixUserString (verifies that the user string is in the heap) | 
|---|
| 414 | MetaData::DataBlob userString; | 
|---|
| 415 | IfFailGo(m_pStgdb->m_MiniMd.m_UserStringHeap.GetBlobWithSizePrefix( | 
|---|
| 416 | ixUserString, | 
|---|
| 417 | &userString)); | 
|---|
| 418 | _ASSERTE(hr == S_OK); | 
|---|
| 419 |  | 
|---|
| 420 | // Get index behind the user string - doesn't overflow, because the user string is in the heap | 
|---|
| 421 | UINT32 ixNextUserString; | 
|---|
| 422 | ixNextUserString = ixUserString + userString.GetSize(); | 
|---|
| 423 |  | 
|---|
| 424 | // Verify that the next index is in the user string heap | 
|---|
| 425 | if (!m_pStgdb->m_MiniMd.m_UserStringHeap.IsValidIndex(ixNextUserString)) | 
|---|
| 426 | {   // The next index is invalid | 
|---|
| 427 | goto ErrExit; | 
|---|
| 428 | } | 
|---|
| 429 | // The next index is valid | 
|---|
| 430 | *pixNextUserString = ixNextUserString; | 
|---|
| 431 | goto Exit; | 
|---|
| 432 |  | 
|---|
| 433 | ErrExit: | 
|---|
| 434 | // Fill output parameters on error | 
|---|
| 435 | *pixNextUserString = 0; | 
|---|
| 436 | // Return S_FALSE if either of the string indexes is invalid (backward API compatibility) | 
|---|
| 437 | hr = S_FALSE; | 
|---|
| 438 | Exit: | 
|---|
| 439 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 440 | return hr; | 
|---|
| 441 | } // RegMeta::GetNextUserString | 
|---|
| 442 |  | 
|---|
| 443 | // -------------------------------------------------------------------------------------- | 
|---|
| 444 | // | 
|---|
| 445 | // Implements public API code:IMetaDataTables::GetNumTables. | 
|---|
| 446 | // | 
|---|
| 447 | HRESULT | 
|---|
| 448 | RegMeta::GetNumTables( | 
|---|
| 449 | __out ULONG *pcTables)  // [OUT] Count of tables. | 
|---|
| 450 | { | 
|---|
| 451 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 452 |  | 
|---|
| 453 | // These are for dumping metadata information. | 
|---|
| 454 | // We probably don't need to do any lock here. | 
|---|
| 455 |  | 
|---|
| 456 | *pcTables = m_pStgdb->m_MiniMd.GetCountTables(); | 
|---|
| 457 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 458 |  | 
|---|
| 459 | return S_OK; | 
|---|
| 460 | } // RegMeta::GetNumTables | 
|---|
| 461 |  | 
|---|
| 462 | // -------------------------------------------------------------------------------------- | 
|---|
| 463 | // | 
|---|
| 464 | // Implements public API code:IMetaDataTables::GetTableIndex. | 
|---|
| 465 | // | 
|---|
| 466 | HRESULT | 
|---|
| 467 | RegMeta::GetTableIndex( | 
|---|
| 468 | ULONG  token,     // [IN] Token for which to get table index. | 
|---|
| 469 | __out ULONG *pixTbl)    // [OUT] Put table index here. | 
|---|
| 470 | { | 
|---|
| 471 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 472 |  | 
|---|
| 473 | // These are for dumping metadata information. | 
|---|
| 474 | // We probably don't need to do any lock here. | 
|---|
| 475 |  | 
|---|
| 476 | *pixTbl = CMiniMdRW::GetTableForToken(token); | 
|---|
| 477 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 478 |  | 
|---|
| 479 | return S_OK; | 
|---|
| 480 | } // RegMeta::GetTableIndex | 
|---|
| 481 |  | 
|---|
| 482 | // -------------------------------------------------------------------------------------- | 
|---|
| 483 | // | 
|---|
| 484 | // Implements public API code:IMetaDataTables::GetTableInfo. | 
|---|
| 485 | // | 
|---|
| 486 | HRESULT | 
|---|
| 487 | RegMeta::GetTableInfo( | 
|---|
| 488 | ULONG        ixTbl,     // [IN] Which table. | 
|---|
| 489 | ULONG       *pcbRow,    // [OUT] Size of a row, bytes. | 
|---|
| 490 | ULONG       *pcRows,    // [OUT] Number of rows. | 
|---|
| 491 | ULONG       *pcCols,    // [OUT] Number of columns in each row. | 
|---|
| 492 | ULONG       *piKey,     // [OUT] Key column, or -1 if none. | 
|---|
| 493 | const char **ppName)    // [OUT] Name of the table. | 
|---|
| 494 | { | 
|---|
| 495 | HRESULT        hr = S_OK; | 
|---|
| 496 | CMiniTableDef *pTbl = NULL; | 
|---|
| 497 |  | 
|---|
| 498 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 499 |  | 
|---|
| 500 | // These are for dumping metadata information. | 
|---|
| 501 | // We probably don't need to do any lock here. | 
|---|
| 502 |  | 
|---|
| 503 | if (ixTbl >= m_pStgdb->m_MiniMd.GetCountTables()) | 
|---|
| 504 | IfFailGo(E_INVALIDARG); | 
|---|
| 505 | pTbl = &m_pStgdb->m_MiniMd.m_TableDefs[ixTbl]; | 
|---|
| 506 | if (pcbRow != NULL) | 
|---|
| 507 | *pcbRow = pTbl->m_cbRec; | 
|---|
| 508 | if (pcRows != NULL) | 
|---|
| 509 | *pcRows = m_pStgdb->m_MiniMd.GetCountRecs(ixTbl); | 
|---|
| 510 | if (pcCols != NULL) | 
|---|
| 511 | *pcCols = pTbl->m_cCols; | 
|---|
| 512 | if (piKey != NULL) | 
|---|
| 513 | *piKey = (pTbl->m_iKey == (BYTE) -1) ? -1 : pTbl->m_iKey; | 
|---|
| 514 | if (ppName != NULL) | 
|---|
| 515 | *ppName = g_Tables[ixTbl].m_pName; | 
|---|
| 516 |  | 
|---|
| 517 | ErrExit: | 
|---|
| 518 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 519 | return hr; | 
|---|
| 520 | } // RegMeta::GetTableInfo | 
|---|
| 521 |  | 
|---|
| 522 | // -------------------------------------------------------------------------------------- | 
|---|
| 523 | // | 
|---|
| 524 | // Implements public API code:IMetaDataTables::GetColumnInfo. | 
|---|
| 525 | // | 
|---|
| 526 | HRESULT | 
|---|
| 527 | RegMeta::GetColumnInfo( | 
|---|
| 528 | ULONG        ixTbl,     // [IN] Which Table | 
|---|
| 529 | ULONG        ixCol,     // [IN] Which Column in the table | 
|---|
| 530 | ULONG       *poCol,     // [OUT] Offset of the column in the row. | 
|---|
| 531 | ULONG       *pcbCol,    // [OUT] Size of a column, bytes. | 
|---|
| 532 | ULONG       *pType,     // [OUT] Type of the column. | 
|---|
| 533 | const char **ppName)    // [OUT] Name of the Column. | 
|---|
| 534 | { | 
|---|
| 535 | HRESULT        hr = S_OK; | 
|---|
| 536 | CMiniTableDef *pTbl = NULL; | 
|---|
| 537 | CMiniColDef   *pCol = NULL; | 
|---|
| 538 |  | 
|---|
| 539 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 540 |  | 
|---|
| 541 | // These are for dumping metadata information. | 
|---|
| 542 | // We probably don't need to do any lock here. | 
|---|
| 543 |  | 
|---|
| 544 | if (ixTbl >= m_pStgdb->m_MiniMd.GetCountTables()) | 
|---|
| 545 | IfFailGo(E_INVALIDARG); | 
|---|
| 546 | pTbl = &m_pStgdb->m_MiniMd.m_TableDefs[ixTbl]; | 
|---|
| 547 | if (ixCol >= pTbl->m_cCols) | 
|---|
| 548 | IfFailGo(E_INVALIDARG); | 
|---|
| 549 | pCol = &pTbl->m_pColDefs[ixCol]; | 
|---|
| 550 | if (poCol != NULL) | 
|---|
| 551 | *poCol = pCol->m_oColumn; | 
|---|
| 552 | if (pcbCol != NULL) | 
|---|
| 553 | *pcbCol = pCol->m_cbColumn; | 
|---|
| 554 | if (pType != NULL) | 
|---|
| 555 | *pType = pCol->m_Type; | 
|---|
| 556 | if (ppName != NULL) | 
|---|
| 557 | *ppName = g_Tables[ixTbl].m_pColNames[ixCol]; | 
|---|
| 558 |  | 
|---|
| 559 | ErrExit: | 
|---|
| 560 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 561 | return hr; | 
|---|
| 562 | } // RegMeta::GetColumnInfo | 
|---|
| 563 |  | 
|---|
| 564 | // -------------------------------------------------------------------------------------- | 
|---|
| 565 | // | 
|---|
| 566 | // Implements public API code:IMetaDataTables::GetCodedTokenInfo. | 
|---|
| 567 | // | 
|---|
| 568 | HRESULT | 
|---|
| 569 | RegMeta::GetCodedTokenInfo( | 
|---|
| 570 | ULONG        ixCdTkn,       // [IN] Which kind of coded token. | 
|---|
| 571 | ULONG       *pcTokens,      // [OUT] Count of tokens. | 
|---|
| 572 | ULONG      **ppTokens,      // [OUT] List of tokens. | 
|---|
| 573 | const char **ppName)        // [OUT] Name of the CodedToken. | 
|---|
| 574 | { | 
|---|
| 575 | HRESULT hr = S_OK; | 
|---|
| 576 |  | 
|---|
| 577 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 578 |  | 
|---|
| 579 | // These are for dumping metadata information. | 
|---|
| 580 | // We probably don't need to do any lock here. | 
|---|
| 581 |  | 
|---|
| 582 | // Validate arguments. | 
|---|
| 583 | if (ixCdTkn >= CDTKN_COUNT) | 
|---|
| 584 | IfFailGo(E_INVALIDARG); | 
|---|
| 585 |  | 
|---|
| 586 | if (pcTokens != NULL) | 
|---|
| 587 | *pcTokens = g_CodedTokens[ixCdTkn].m_cTokens; | 
|---|
| 588 | if (ppTokens != NULL) | 
|---|
| 589 | *ppTokens = (ULONG*)g_CodedTokens[ixCdTkn].m_pTokens; | 
|---|
| 590 | if (ppName != NULL) | 
|---|
| 591 | *ppName = g_CodedTokens[ixCdTkn].m_pName; | 
|---|
| 592 |  | 
|---|
| 593 | ErrExit: | 
|---|
| 594 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 595 | return hr; | 
|---|
| 596 | } // RegMeta::GetCodedTokenInfo | 
|---|
| 597 |  | 
|---|
| 598 | // -------------------------------------------------------------------------------------- | 
|---|
| 599 | // | 
|---|
| 600 | // Implements public API code:IMetaDataTables::GetRow. | 
|---|
| 601 | // | 
|---|
| 602 | HRESULT | 
|---|
| 603 | RegMeta::GetRow( | 
|---|
| 604 | ULONG  ixTbl,       // [IN] Which table. | 
|---|
| 605 | ULONG  rid,         // [IN] Which row. | 
|---|
| 606 | void **ppRow)       // [OUT] Put pointer to row here. | 
|---|
| 607 | { | 
|---|
| 608 | HRESULT hr = S_OK; | 
|---|
| 609 |  | 
|---|
| 610 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 611 |  | 
|---|
| 612 | // These are for dumping metadata information. | 
|---|
| 613 | // We probably don't need to do any lock here. | 
|---|
| 614 |  | 
|---|
| 615 | // Validate arguments. | 
|---|
| 616 | if (ixTbl >= m_pStgdb->m_MiniMd.GetCountTables()) | 
|---|
| 617 | IfFailGo(E_INVALIDARG); | 
|---|
| 618 | if (rid == 0 || rid > m_pStgdb->m_MiniMd.m_Schema.m_cRecs[ixTbl]) | 
|---|
| 619 | IfFailGo(E_INVALIDARG); | 
|---|
| 620 |  | 
|---|
| 621 | // Get the row. | 
|---|
| 622 | IfFailGo(m_pStgdb->m_MiniMd.getRow(ixTbl, rid, ppRow)); | 
|---|
| 623 |  | 
|---|
| 624 | ErrExit: | 
|---|
| 625 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 626 | return hr; | 
|---|
| 627 | } // RegMeta::GetRow | 
|---|
| 628 |  | 
|---|
| 629 | // -------------------------------------------------------------------------------------- | 
|---|
| 630 | // | 
|---|
| 631 | // Implements public API code:IMetaDataTables::GetColumn. | 
|---|
| 632 | // | 
|---|
| 633 | HRESULT | 
|---|
| 634 | RegMeta::GetColumn( | 
|---|
| 635 | ULONG  ixTbl,       // [IN] Which table. | 
|---|
| 636 | ULONG  ixCol,       // [IN] Which column. | 
|---|
| 637 | ULONG  rid,         // [IN] Which row. | 
|---|
| 638 | ULONG *pVal)        // [OUT] Put the column contents here. | 
|---|
| 639 | { | 
|---|
| 640 | HRESULT        hr = S_OK; | 
|---|
| 641 | CMiniColDef   *pCol = NULL; | 
|---|
| 642 | CMiniTableDef *pTbl = NULL; | 
|---|
| 643 |  | 
|---|
| 644 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 645 |  | 
|---|
| 646 | // These are for dumping metadata information. | 
|---|
| 647 | // We probably don't need to do any lock here. | 
|---|
| 648 |  | 
|---|
| 649 | void *pRow = NULL;      // Row with data. | 
|---|
| 650 |  | 
|---|
| 651 | // Validate arguments. | 
|---|
| 652 | if (ixTbl >= m_pStgdb->m_MiniMd.GetCountTables()) | 
|---|
| 653 | IfFailGo(E_INVALIDARG); | 
|---|
| 654 | pTbl = &m_pStgdb->m_MiniMd.m_TableDefs[ixTbl]; | 
|---|
| 655 | if (ixCol >= pTbl->m_cCols) | 
|---|
| 656 | IfFailGo(E_INVALIDARG); | 
|---|
| 657 | if (rid == 0 || rid > m_pStgdb->m_MiniMd.m_Schema.m_cRecs[ixTbl]) | 
|---|
| 658 | IfFailGo(E_INVALIDARG); | 
|---|
| 659 |  | 
|---|
| 660 | // Get the row. | 
|---|
| 661 | IfFailGo(m_pStgdb->m_MiniMd.getRow(ixTbl, rid, &pRow)); | 
|---|
| 662 |  | 
|---|
| 663 | // Is column a token column? | 
|---|
| 664 | pCol = &pTbl->m_pColDefs[ixCol]; | 
|---|
| 665 | if (pCol->m_Type <= iCodedTokenMax) | 
|---|
| 666 | { | 
|---|
| 667 | *pVal = m_pStgdb->m_MiniMd.GetToken(ixTbl, ixCol, pRow); | 
|---|
| 668 | } | 
|---|
| 669 | else | 
|---|
| 670 | { | 
|---|
| 671 | *pVal = m_pStgdb->m_MiniMd.GetCol(ixTbl, ixCol, pRow); | 
|---|
| 672 | } | 
|---|
| 673 |  | 
|---|
| 674 | ErrExit: | 
|---|
| 675 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 676 | return hr; | 
|---|
| 677 | } // RegMeta::GetColumn | 
|---|
| 678 |  | 
|---|
| 679 | // -------------------------------------------------------------------------------------- | 
|---|
| 680 | // | 
|---|
| 681 | // Implements public API code:IMetaDataTables2::GetMetaDataStorage. | 
|---|
| 682 | // | 
|---|
| 683 | HRESULT | 
|---|
| 684 | RegMeta::GetMetaDataStorage( | 
|---|
| 685 | const void **ppvMd,     // [OUT] put pointer to MD section here (aka, 'BSJB'). | 
|---|
| 686 | ULONG       *pcbMd)     // [OUT] put size of the stream here. | 
|---|
| 687 | { | 
|---|
| 688 | HRESULT hr = S_OK; | 
|---|
| 689 |  | 
|---|
| 690 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 691 | REGMETA_POSSIBLE_INTERNAL_POINTER_EXPOSED(); | 
|---|
| 692 |  | 
|---|
| 693 | hr = m_pStgdb->GetRawData(ppvMd, pcbMd); | 
|---|
| 694 |  | 
|---|
| 695 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 696 | return hr; | 
|---|
| 697 | } // RegMeta::GetMetaDataStorage | 
|---|
| 698 |  | 
|---|
| 699 | // -------------------------------------------------------------------------------------- | 
|---|
| 700 | // | 
|---|
| 701 | // Implements public API code:IMetaDataTables2::GetMetaDataStreamInfo. | 
|---|
| 702 | // | 
|---|
| 703 | HRESULT | 
|---|
| 704 | RegMeta::GetMetaDataStreamInfo( | 
|---|
| 705 | ULONG        ix,            // [IN] Stream ordinal desired. | 
|---|
| 706 | const char **ppchName,      // [OUT] put pointer to stream name here. | 
|---|
| 707 | const void **ppv,           // [OUT] put pointer to MD stream here. | 
|---|
| 708 | ULONG       *pcb)           // [OUT] put size of the stream here. | 
|---|
| 709 | { | 
|---|
| 710 | HRESULT hr = S_OK; | 
|---|
| 711 |  | 
|---|
| 712 | BEGIN_ENTRYPOINT_NOTHROW; | 
|---|
| 713 | REGMETA_POSSIBLE_INTERNAL_POINTER_EXPOSED(); | 
|---|
| 714 |  | 
|---|
| 715 | hr = m_pStgdb->GetRawStreamInfo(ix, ppchName, ppv, pcb); | 
|---|
| 716 |  | 
|---|
| 717 | END_ENTRYPOINT_NOTHROW; | 
|---|
| 718 | return hr; | 
|---|
| 719 | } // RegMeta::GetMetaDataStreamInfo | 
|---|
| 720 |  | 
|---|