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// MetaModel.cpp -- Base portion of compressed COM+ metadata.
6//
7
8//
9//*****************************************************************************
10#include "stdafx.h"
11
12#include <metamodel.h>
13#include <corerror.h>
14#include <posterror.h>
15
16//*****************************************************************************
17// meta-meta model.
18//*****************************************************************************
19
20//-----------------------------------------------------------------------------
21// Start of column definitions.
22//-----------------------------------------------------------------------------
23// Column type, offset, size.
24#define SCHEMA_TABLE_START(tbl) static CMiniColDef r##tbl##Cols[] = {
25#define SCHEMA_ITEM_NOFIXED()
26#define SCHEMA_ITEM_ENTRY(col,typ) {typ, 0,0},
27#define SCHEMA_ITEM_ENTRY2(col,typ,ofs,siz) {typ, ofs, siz},
28#define SCHEMA_ITEM(tbl,typ,col) SCHEMA_ITEM_ENTRY2(col, i##typ, offsetof(tbl##Rec,m_##col), sizeof(((tbl##Rec*)(0))->m_##col))
29#define SCHEMA_ITEM_RID(tbl,col,tbl2) SCHEMA_ITEM_ENTRY(col,TBL_##tbl2)
30#define SCHEMA_ITEM_STRING(tbl,col) SCHEMA_ITEM_ENTRY(col,iSTRING)
31#define SCHEMA_ITEM_GUID(tbl,col) SCHEMA_ITEM_ENTRY(col,iGUID)
32#define SCHEMA_ITEM_BLOB(tbl,col) SCHEMA_ITEM_ENTRY(col,iBLOB)
33#define SCHEMA_ITEM_CDTKN(tbl,col,tkns) SCHEMA_ITEM_ENTRY(col,iCodedToken+(CDTKN_##tkns))
34#define SCHEMA_TABLE_END(tbl) };
35//-----------------------------------------------------------------------------
36#include "metamodelcolumndefs.h"
37//-----------------------------------------------------------------------------
38#undef SCHEMA_TABLE_START
39#undef SCHEMA_ITEM_NOFIXED
40#undef SCHEMA_ITEM_ENTRY
41#undef SCHEMA_ITEM_ENTRY2
42#undef SCHEMA_ITEM
43#undef SCHEMA_ITEM_RID
44#undef SCHEMA_ITEM_STRING
45#undef SCHEMA_ITEM_GUID
46#undef SCHEMA_ITEM_BLOB
47#undef SCHEMA_ITEM_CDTKN
48#undef SCHEMA_TABLE_END
49//-----------------------------------------------------------------------------
50
51//-----------------------------------------------------------------------------
52// Column names.
53#define SCHEMA_TABLE_START(tbl) static const char *r##tbl##ColNames[] = {
54#define SCHEMA_ITEM_NOFIXED()
55#define SCHEMA_ITEM_ENTRY(col,typ) #col,
56#define SCHEMA_ITEM_ENTRY2(col,typ,ofs,siz) #col,
57#define SCHEMA_ITEM(tbl,typ,col) SCHEMA_ITEM_ENTRY2(col, i##typ, offsetof(tbl##Rec,m_##col), sizeof(((tbl##Rec*)(0))->m_##col))
58#define SCHEMA_ITEM_RID(tbl,col,tbl2) SCHEMA_ITEM_ENTRY(col,TBL_##tbl2)
59#define SCHEMA_ITEM_STRING(tbl,col) SCHEMA_ITEM_ENTRY(col,iSTRING)
60#define SCHEMA_ITEM_GUID(tbl,col) SCHEMA_ITEM_ENTRY(col,iGUID)
61#define SCHEMA_ITEM_BLOB(tbl,col) SCHEMA_ITEM_ENTRY(col,iBLOB)
62#define SCHEMA_ITEM_CDTKN(tbl,col,tkns) SCHEMA_ITEM_ENTRY(col,iCodedToken+(CDTKN_##tkns))
63#define SCHEMA_TABLE_END(tbl) };
64//-----------------------------------------------------------------------------
65#include "metamodelcolumndefs.h"
66//-----------------------------------------------------------------------------
67#undef SCHEMA_TABLE_START
68#undef SCHEMA_ITEM_NOFIXED
69#undef SCHEMA_ITEM_ENTRY
70#undef SCHEMA_ITEM_ENTRY2
71#undef SCHEMA_ITEM
72#undef SCHEMA_ITEM_RID
73#undef SCHEMA_ITEM_STRING
74#undef SCHEMA_ITEM_GUID
75#undef SCHEMA_ITEM_BLOB
76#undef SCHEMA_ITEM_CDTKN
77#undef SCHEMA_TABLE_END
78
79//-----------------------------------------------------------------------------
80// End of column definitions.
81//-----------------------------------------------------------------------------
82
83// Define the array of Coded Token Definitions.
84#define MiniMdCodedToken(x) {lengthof(CMiniMdBase::mdt##x), CMiniMdBase::mdt##x, #x},
85const CCodedTokenDef g_CodedTokens [] = {
86 MiniMdCodedTokens()
87};
88#undef MiniMdCodedToken
89
90// Define the array of Table Definitions.
91#undef MiniMdTable
92#define MiniMdTable(x) { { r##x##Cols, lengthof(r##x##Cols), x##Rec::COL_KEY, 0 }, r##x##ColNames, #x},
93const CMiniTableDefEx g_Tables[TBL_COUNT] = {
94 MiniMdTables()
95};
96
97// Define a table descriptor for the obsolete v1.0 GenericParam table definition.
98const CMiniTableDefEx g_Table_GenericParamV1_1 = { { rGenericParamV1_1Cols, lengthof(rGenericParamV1_1Cols), GenericParamV1_1Rec::COL_KEY, 0 }, rGenericParamV1_1ColNames, "GenericParamV1_"};
99
100
101
102// Define the array of Ptr Tables. This is initialized to TBL_COUNT here.
103// The correct values will be set in the constructor for MiniMdRW.
104#undef MiniMdTable
105#define MiniMdTable(x) { TBL_COUNT, 0 },
106TblCol g_PtrTableIxs[TBL_COUNT] = {
107 MiniMdTables()
108};
109
110//*****************************************************************************
111// Initialize a new schema.
112//*****************************************************************************
113HRESULT
114CMiniMdSchema::InitNew(
115 MetadataVersion mdVersion)
116{
117 // Make sure the tables fit in the mask.
118 _ASSERTE((sizeof(m_maskvalid) * 8) > TBL_COUNT);
119
120 m_ulReserved = 0;
121
122 if(mdVersion == MDVersion1)
123 {
124 m_major = METAMODEL_MAJOR_VER_V1_0;
125 m_minor = METAMODEL_MINOR_VER_V1_0;
126 }
127 else if (mdVersion == MDVersion2)
128 {
129 m_major = METAMODEL_MAJOR_VER;
130 m_minor = METAMODEL_MINOR_VER;
131 }
132 else
133 {
134 return E_INVALIDARG;
135 }
136
137 m_heaps = 0;
138 m_rid = 0;
139 m_maskvalid = 0;
140 m_sorted = 0;
141 memset(m_cRecs, 0, sizeof(m_cRecs));
142 m_ulExtra = 0;
143
144 return S_OK;
145} // CMiniMdSchema::InitNew
146
147//*****************************************************************************
148// Compress a schema into a compressed version of the schema.
149//*****************************************************************************
150ULONG
151CMiniMdSchema::SaveTo(
152 void *pvData)
153{
154 ULONG ulData; // Bytes stored.
155 CMiniMdSchema *pDest = reinterpret_cast<CMiniMdSchema*>(pvData);
156 const unsigned __int64 one = 1;
157
158 // Make sure the tables fit in the mask.
159 _ASSERTE((sizeof(m_maskvalid) * 8) > TBL_COUNT);
160
161 // Set the flag for the extra data.
162#if defined(EXTRA_DATA)
163 if (m_ulExtra != 0)
164 {
165 m_heaps |= EXTRA_DATA;
166 }
167 else
168#endif // 0
169 {
170 m_heaps &= ~EXTRA_DATA;
171 }
172
173 // Minor version is preset when we instantiate the MiniMd.
174
175 // Make sure we're saving out a version that Beta1 version can read
176 _ASSERTE((m_major == METAMODEL_MAJOR_VER && m_minor == METAMODEL_MINOR_VER) ||
177 (m_major == METAMODEL_MAJOR_VER_B1 && m_minor == METAMODEL_MINOR_VER_B1) ||
178 (m_major == METAMODEL_MAJOR_VER_V1_0 && m_minor == METAMODEL_MINOR_VER_V1_0));
179
180 // Transfer the fixed fields.
181 *static_cast<CMiniMdSchemaBase*>(pDest) = *static_cast<CMiniMdSchemaBase*>(this);
182 static_cast<CMiniMdSchemaBase*>(pDest)->ConvertEndianness();
183 ulData = sizeof(CMiniMdSchemaBase);
184
185 // Transfer the variable fields.
186 m_maskvalid = 0;
187 for (int iSrc=0, iDst=0; iSrc<TBL_COUNT; ++iSrc)
188 {
189 if (m_cRecs[iSrc] != 0)
190 {
191 pDest->m_cRecs[iDst++] = VAL32(m_cRecs[iSrc]);
192 m_maskvalid |= (one << iSrc);
193 ulData += sizeof(m_cRecs[iSrc]);
194 }
195 }
196 // Refresh the mask.
197 pDest->m_maskvalid = VAL64(m_maskvalid);
198
199#if defined(EXTRA_DATA)
200 // Store the extra data.
201 if (m_ulExtra != 0)
202 {
203 *reinterpret_cast<ULONG*>(&pDest->m_cRecs[iDst]) = VAL32(m_ulExtra);
204 ulData += sizeof(ULONG);
205 }
206#endif // 0
207 return ulData;
208} // CMiniMdSchema::SaveTo
209
210//*****************************************************************************
211// Load a schema from a compressed version of the schema.
212// Returns count of bytes consumed. -1 if error.
213//*****************************************************************************
214ULONG
215CMiniMdSchema::LoadFrom(
216 const void *pvData, // Data to load from.
217 ULONG cbData) // Amount of data available.
218{
219 ULONG ulData; // Bytes consumed.
220
221 ulData = sizeof(CMiniMdSchemaBase);
222
223 // Be sure we can get the base part.
224 if (cbData < ulData)
225 return (ULONG)(-1);
226
227 // Transfer the fixed fields. The (void*) casts prevents the compiler
228 // from making bad assumptions about the alignment.
229 memcpy((void *)this, (void *)pvData, sizeof(CMiniMdSchemaBase));
230 static_cast<CMiniMdSchemaBase*>(this)->ConvertEndianness();
231
232 unsigned __int64 maskvalid = m_maskvalid;
233
234 // Transfer the variable fields.
235 memset(m_cRecs, 0, sizeof(m_cRecs));
236 int iDst;
237 for (iDst = 0; iDst < TBL_COUNT; ++iDst, maskvalid >>= 1)
238 {
239 if ((maskvalid & 1) != 0)
240 {
241 // Check integer overflow for: ulData + sizeof(UINT32)
242 ULONG ulDataTemp;
243 if (!ClrSafeInt<ULONG>::addition(ulData, sizeof(UINT32), ulDataTemp))
244 {
245 return (ULONG)(-1);
246 }
247 // Verify that the data is there before touching it.
248 if (cbData < (ulData + sizeof(UINT32)))
249 return (ULONG)(-1);
250
251 m_cRecs[iDst] = GET_UNALIGNED_VAL32((const BYTE *)pvData + ulData);
252 // It's safe to sum, because we checked integer overflow above
253 ulData += sizeof(UINT32);
254 }
255 }
256 // Also accumulate the sizes of any counters that we don't understand.
257 for (iDst = TBL_COUNT; (maskvalid != 0) && (iDst < ((int)sizeof(m_maskvalid) * 8)); ++iDst, maskvalid >>= 1)
258 {
259 if ((maskvalid & 1) != 0)
260 {
261 // Check integer overflow for: ulData += sizeof(UINT32);
262 if (!ClrSafeInt<ULONG>::addition(ulData, sizeof(UINT32), ulData))
263 {
264 return (ULONG)(-1);
265 }
266 // Did we go past end of buffer?
267 if (cbData < ulData)
268 {
269 return (ULONG)(-1);
270 }
271 }
272 }
273
274 // Retrieve the extra 4 bytes data.
275 if ((m_heaps & EXTRA_DATA) != 0)
276 {
277 // Check integer overflow for: ulData + sizeof(UINT32)
278 ULONG ulDataTemp;
279 if (!ClrSafeInt<ULONG>::addition(ulData, sizeof(UINT32), ulDataTemp))
280 {
281 return (ULONG)(-1);
282 }
283 // Verify that the 4 bytes data is there before touching it.
284 if (cbData < (ulData + sizeof(UINT32)))
285 return (ULONG)(-1);
286
287 m_ulExtra = GET_UNALIGNED_VAL32((const BYTE *)pvData + ulData);
288 // Check the size we used for buffer overflow verification above
289 ulData += sizeof(UINT32);
290 }
291
292 // Did we go past end of buffer?
293 if (cbData < ulData)
294 return (ULONG)(-1);
295
296 return ulData;
297} // CMiniMdSchema::LoadFrom
298
299
300const mdToken CMiniMdBase::mdtTypeDefOrRef[3] = {
301 mdtTypeDef,
302 mdtTypeRef,
303 mdtTypeSpec
304};
305
306// This array needs to be ordered the same as the source tables are processed (currently
307// {field, param, property}) for binary search.
308const mdToken CMiniMdBase::mdtHasConstant[3] = {
309 mdtFieldDef,
310 mdtParamDef,
311 mdtProperty
312};
313
314const mdToken CMiniMdBase::mdtHasCustomAttribute[24] = {
315 mdtMethodDef,
316 mdtFieldDef,
317 mdtTypeRef,
318 mdtTypeDef,
319 mdtParamDef,
320 mdtInterfaceImpl,
321 mdtMemberRef,
322 mdtModule,
323 mdtPermission,
324 mdtProperty,
325 mdtEvent,
326 mdtSignature,
327 mdtModuleRef,
328 mdtTypeSpec,
329 mdtAssembly,
330 mdtAssemblyRef,
331 mdtFile,
332 mdtExportedType,
333 mdtManifestResource,
334 mdtGenericParam,
335 mdtGenericParamConstraint,
336 mdtMethodSpec
337};
338
339const mdToken CMiniMdBase::mdtHasFieldMarshal[2] = {
340 mdtFieldDef,
341 mdtParamDef,
342};
343
344const mdToken CMiniMdBase::mdtHasDeclSecurity[3] = {
345 mdtTypeDef,
346 mdtMethodDef,
347 mdtAssembly
348};
349
350const mdToken CMiniMdBase::mdtMemberRefParent[5] = {
351 mdtTypeDef,
352 mdtTypeRef,
353 mdtModuleRef,
354 mdtMethodDef,
355 mdtTypeSpec
356};
357
358const mdToken CMiniMdBase::mdtHasSemantic[2] = {
359 mdtEvent,
360 mdtProperty,
361};
362
363const mdToken CMiniMdBase::mdtMethodDefOrRef[2] = {
364 mdtMethodDef,
365 mdtMemberRef
366};
367
368const mdToken CMiniMdBase::mdtMemberForwarded[2] = {
369 mdtFieldDef,
370 mdtMethodDef
371};
372
373const mdToken CMiniMdBase::mdtImplementation[3] = {
374 mdtFile,
375 mdtAssemblyRef,
376 mdtExportedType
377};
378
379const mdToken CMiniMdBase::mdtCustomAttributeType[5] = {
380 0,
381 0,
382 mdtMethodDef,
383 mdtMemberRef,
384 0
385};
386
387const mdToken CMiniMdBase::mdtResolutionScope[4] = {
388 mdtModule,
389 mdtModuleRef,
390 mdtAssemblyRef,
391 mdtTypeRef
392};
393
394const mdToken CMiniMdBase::mdtTypeOrMethodDef[2] = {
395 mdtTypeDef,
396 mdtMethodDef
397};
398
399const int CMiniMdBase::m_cb[] = {0,1,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5};
400
401//*****************************************************************************
402// Function to encode a token into fewer bits. Looks up token type in array of types.
403//*****************************************************************************
404//<TODO>@consider whether this could be a binary search.</TODO>
405ULONG
406CMiniMdBase::encodeToken(
407 RID rid, // Rid to encode.
408 mdToken typ, // Token type to encode.
409 const mdToken rTokens[], // Table of valid token.
410 ULONG32 cTokens) // Size of the table.
411{
412 mdToken tk = TypeFromToken(typ);
413 size_t ix;
414 for (ix = 0; ix < cTokens; ++ix)
415 {
416 if (rTokens[ix] == tk)
417 break;
418 }
419 _ASSERTE(ix < cTokens);
420 if (ix >= cTokens)
421 return mdTokenNil;
422 //<TODO>@FUTURE: make compile-time calculation</TODO>
423 return (ULONG)((rid << m_cb[cTokens]) | ix);
424} // CMiniMd::encodeToken
425
426
427//*****************************************************************************
428// Helpers for populating the hard-coded schema.
429//*****************************************************************************
430inline BYTE cbRID(ULONG ixMax) { return ixMax > USHRT_MAX ? (BYTE) sizeof(ULONG) : (BYTE) sizeof(USHORT); }
431
432#define _CBTKN(cRecs,tkns) cbRID(cRecs << m_cb[lengthof(tkns)])
433
434//*****************************************************************************
435// Constructor.
436//*****************************************************************************
437CMiniMdBase::CMiniMdBase()
438{
439#undef MiniMdTable
440#define MiniMdTable(tbl) \
441 m_TableDefs[TBL_##tbl] = g_Tables[TBL_##tbl].m_Def; \
442 m_TableDefs[TBL_##tbl].m_pColDefs = BYTEARRAY_TO_COLDES(s_##tbl##Col);
443 MiniMdTables()
444
445 m_TblCount = TBL_COUNT;
446 _ASSERTE(TBL_COUNT == TBL_COUNT_V2); // v2 counts.
447
448 m_fVerifiedByTrustedSource = FALSE;
449
450 // Validator depends on the Table Ids and the Token Ids being identical.
451 // Catch it if this ever breaks.
452 _ASSERTE((TypeFromToken(mdtModule) >> 24) == TBL_Module);
453 _ASSERTE((TypeFromToken(mdtTypeRef) >> 24) == TBL_TypeRef);
454 _ASSERTE((TypeFromToken(mdtTypeDef) >> 24) == TBL_TypeDef);
455 _ASSERTE((TypeFromToken(mdtFieldDef) >> 24) == TBL_Field);
456 _ASSERTE((TypeFromToken(mdtMethodDef) >> 24) == TBL_Method);
457 _ASSERTE((TypeFromToken(mdtParamDef) >> 24) == TBL_Param);
458 _ASSERTE((TypeFromToken(mdtInterfaceImpl) >> 24) == TBL_InterfaceImpl);
459 _ASSERTE((TypeFromToken(mdtMemberRef) >> 24) == TBL_MemberRef);
460 _ASSERTE((TypeFromToken(mdtCustomAttribute) >> 24) == TBL_CustomAttribute);
461 _ASSERTE((TypeFromToken(mdtPermission) >> 24) == TBL_DeclSecurity);
462 _ASSERTE((TypeFromToken(mdtSignature) >> 24) == TBL_StandAloneSig);
463 _ASSERTE((TypeFromToken(mdtEvent) >> 24) == TBL_Event);
464 _ASSERTE((TypeFromToken(mdtProperty) >> 24) == TBL_Property);
465 _ASSERTE((TypeFromToken(mdtModuleRef) >> 24) == TBL_ModuleRef);
466 _ASSERTE((TypeFromToken(mdtTypeSpec) >> 24) == TBL_TypeSpec);
467 _ASSERTE((TypeFromToken(mdtAssembly) >> 24) == TBL_Assembly);
468 _ASSERTE((TypeFromToken(mdtAssemblyRef) >> 24) == TBL_AssemblyRef);
469 _ASSERTE((TypeFromToken(mdtFile) >> 24) == TBL_File);
470 _ASSERTE((TypeFromToken(mdtExportedType) >> 24) == TBL_ExportedType);
471 _ASSERTE((TypeFromToken(mdtManifestResource) >> 24) == TBL_ManifestResource);
472 _ASSERTE((TypeFromToken(mdtGenericParam) >> 24) == TBL_GenericParam);
473 _ASSERTE((TypeFromToken(mdtMethodSpec) >> 24) == TBL_MethodSpec);
474 _ASSERTE((TypeFromToken(mdtGenericParamConstraint) >> 24) == TBL_GenericParamConstraint);
475} // CMiniMdBase::CMiniMdBase
476
477
478//*****************************************************************************
479// Destructor.
480//*****************************************************************************
481CMiniMdBase::~CMiniMdBase()
482{
483 for (ULONG i = 0; i < m_TblCount; i++)
484 {
485 if ((m_TableDefs[i].m_pColDefs != NULL) && UsesAllocatedMemory(m_TableDefs[i].m_pColDefs))
486 {
487 delete[] COLDES_TO_BYTEARRAY(m_TableDefs[i].m_pColDefs);
488 m_TableDefs[i].m_pColDefs = NULL;
489 }
490 }
491} // CMiniMdBase::~CMiniMdBase
492
493//*****************************************************************************
494// Build the schema based on the header data provided.
495// Handle all supported versions, and adjust data structures appropriately.
496//*****************************************************************************
497HRESULT
498CMiniMdBase::SchemaPopulate(
499 const void *pvData, // Pointer to the buffer.
500 ULONG cbData, // Size of the buffer.
501 ULONG *pcbUsed) // Put size of the header here.
502{
503 HRESULT hr;
504 ULONG cb; // Bytes read for header.
505 ULONG cbTables; // Bytes needed for tables.
506 ULONG cbTotal; // Bytes read for header + needed for tables.
507
508 // Uncompress the schema from the buffer into our structures.
509 cb = m_Schema.LoadFrom(pvData, cbData);
510
511 if ((cb > cbData) || (cb == (ULONG)(-1)))
512 {
513 Debug_ReportError("Schema is not in MetaData block.");
514 return PostError(CLDB_E_FILE_CORRUPT);
515 }
516
517 // Is this the "native" version of the metadata for this runtime?
518 if ((m_Schema.m_major != METAMODEL_MAJOR_VER) || (m_Schema.m_minor != METAMODEL_MINOR_VER))
519 {
520 // No it's not. Is this an older version that we support?
521
522 // Is this v1.0?
523 if ((m_Schema.m_major == METAMODEL_MAJOR_VER_V1_0) &&
524 (m_Schema.m_minor == METAMODEL_MINOR_VER_V1_0))
525 {
526 // Older version has fewer tables.
527 m_TblCount = TBL_COUNT_V1;
528 }
529 else if ((m_Schema.m_major == METAMODEL_MAJOR_VER_B1) &&
530 (m_Schema.m_minor == METAMODEL_MINOR_VER_B1))
531 {
532 // 1.1 had a different type of GenericParam table
533 m_TableDefs[TBL_GenericParam] = g_Table_GenericParamV1_1.m_Def;
534 m_TableDefs[TBL_GenericParam].m_pColDefs = BYTEARRAY_TO_COLDES(s_GenericParamCol);
535 }
536 else
537 { // We don't support this version of the metadata
538 Debug_ReportError("Unsupported version of MetaData.");
539 return PostError(CLDB_E_FILE_OLDVER, m_Schema.m_major, m_Schema.m_minor);
540 }
541 }
542
543 // Populate the schema, based on the row counts and heap sizes.
544 IfFailRet(SchemaPopulate2(&cbTables));
545
546 // Check that header plus tables fits within the size given.
547 if (!ClrSafeInt<ULONG>::addition(cb, cbTables, cbTotal) || (cbTotal > cbData))
548 {
549 Debug_ReportError("Tables are not within MetaData block.");
550 return PostError(CLDB_E_FILE_CORRUPT);
551 }
552
553 *pcbUsed = cb;
554 return S_OK;
555} // CMiniMdBase::SchemaPopulate
556
557//*****************************************************************************
558// Initialize from another MD
559//*****************************************************************************
560HRESULT
561CMiniMdBase::SchemaPopulate(
562 const CMiniMdBase &that)
563{
564 HRESULT hr;
565 // Copy over the schema.
566 m_Schema = that.m_Schema;
567
568 // Adjust for prior versions.
569 if (m_Schema.m_major != METAMODEL_MAJOR_VER || m_Schema.m_minor != METAMODEL_MINOR_VER)
570 {
571 if ((m_Schema.m_major == METAMODEL_MAJOR_VER_V1_0) && (m_Schema.m_minor == METAMODEL_MINOR_VER_V1_0))
572 { // Older version has fewer tables.
573 m_TblCount = that.m_TblCount;
574 _ASSERTE(m_TblCount == TBL_COUNT_V1);
575 }
576 else if (m_Schema.m_major == METAMODEL_MAJOR_VER_B1 && m_Schema.m_minor == METAMODEL_MINOR_VER_B1)
577 {
578 // 1.1 had a different type of GenericParam table
579 m_TableDefs[TBL_GenericParam] = g_Table_GenericParamV1_1.m_Def;
580 m_TableDefs[TBL_GenericParam].m_pColDefs = BYTEARRAY_TO_COLDES(s_GenericParamCol);
581 }
582 // Is it a supported old version? This should never fail!
583 else
584 {
585 Debug_ReportError("Initializing on an unknown schema version");
586 return PostError(CLDB_E_FILE_OLDVER, m_Schema.m_major,m_Schema.m_minor);
587 }
588 }
589
590 IfFailRet(SchemaPopulate2(NULL));
591
592 return S_OK;
593} // CMiniMdBase::SchemaPopulate
594
595//*****************************************************************************
596// Iterate the tables, and fix the column sizes, based on size of data.
597//*****************************************************************************
598HRESULT CMiniMdBase::SchemaPopulate2(
599 ULONG *pcbTables, // [out, optional] Put size needed for tables here.
600 int bExtra) // Reserve an extra bit for rid columns?
601{
602 HRESULT hr; // A result.
603 ULONG cbTotal = 0; // Total size of all tables.
604
605 // How big are the various pool inidices?
606 m_iStringsMask = (m_Schema.m_heaps & CMiniMdSchema::HEAP_STRING_4) ? 0xffffffff : 0xffff;
607 m_iGuidsMask = (m_Schema.m_heaps & CMiniMdSchema::HEAP_GUID_4) ? 0xffffffff : 0xffff;
608 m_iBlobsMask = (m_Schema.m_heaps & CMiniMdSchema::HEAP_BLOB_4) ? 0xffffffff : 0xffff;
609
610 // Make extra bits exactly zero or one bit.
611 if (bExtra)
612 bExtra = 1;
613
614 // Until ENC, make extra bits exactly zero.
615 bExtra = 0;
616
617 // For each table...
618 for (int ixTbl = 0; ixTbl < (int)m_TblCount; ++ixTbl)
619 {
620 IfFailRet(InitColsForTable(m_Schema, ixTbl, &m_TableDefs[ixTbl], bExtra, TRUE));
621
622 // Accumulate size of this table.
623 // Check integer overflow for table size: USHORT * ULONG: m_TableDefs[ixTbl].m_cbRec * GetCountRecs(ixTbl)
624 ULONG cbTable;
625 if (!ClrSafeInt<ULONG>::multiply(m_TableDefs[ixTbl].m_cbRec, GetCountRecs(ixTbl), cbTable))
626 {
627 Debug_ReportError("Table is too large - size overflow.");
628 return PostError(CLDB_E_FILE_CORRUPT);
629 }
630 // Check integer overflow for all tables so far: cbTotal += cbTable
631 if (!ClrSafeInt<ULONG>::addition(cbTotal, cbTable, cbTotal))
632 {
633 Debug_ReportError("Tables are too large - size overflow.");
634 return PostError(CLDB_E_FILE_CORRUPT);
635 }
636 }
637 // Check that unused table (e.g. generic tables in v1 format) are empty
638 for (ULONG ixTbl = m_TblCount; ixTbl < TBL_COUNT; ixTbl++)
639 {
640 // All unused tables have to be empty - malicious assemblies can have v1 format version, but can
641 // contain non-empty v2-only tables, this will catch it and refuse to load such assemblies
642 if (GetCountRecs(ixTbl) != 0)
643 {
644 Debug_ReportError("Invalid table present - 2.0 table in v1.x image.");
645 return PostError(CLDB_E_FILE_CORRUPT);
646 }
647 }
648
649 // Let caller know sizes required.
650 if (pcbTables != NULL)
651 *pcbTables = cbTotal;
652
653 return S_OK;
654} // CMiniMdBase::SchemaPopulate2
655
656//*****************************************************************************
657// Get the template table definition for a given table.
658//*****************************************************************************
659const CMiniTableDef *
660CMiniMdBase::GetTableDefTemplate(
661 int ixTbl)
662{
663 const CMiniTableDef *pTemplate; // the return value.
664
665 // Return the table definition for the given table. Account for version of schema.
666 if ((m_Schema.m_major == METAMODEL_MAJOR_VER_B1) && (m_Schema.m_minor == METAMODEL_MINOR_VER_B1) && (ixTbl == TBL_GenericParam))
667 {
668 pTemplate = &g_Table_GenericParamV1_1.m_Def;
669 }
670 else
671 {
672 pTemplate = &g_Tables[ixTbl].m_Def;
673 }
674
675 return pTemplate;
676} // CMiniMdBase::GetTableDefTemplate
677
678//*****************************************************************************
679// Initialize the column defs for a table, based on their types and sizes.
680//*****************************************************************************
681HRESULT
682CMiniMdBase::InitColsForTable(
683 CMiniMdSchema &Schema, // Schema with sizes.
684 int ixTbl, // Index of table to init.
685 CMiniTableDef *pTable, // Table to init.
686 int bExtra, // Extra bits for rid column.
687 BOOL fUsePointers) // Should we have pTable point to it's Column Descriptors, or
688 // should we write the data into the structure
689{
690 const CMiniTableDef *pTemplate; // Template table definition.
691 CMiniColDef pCols[9]; // The col defs to init.
692 BYTE iOffset; // Running size of a record.
693 BYTE iSize; // Size of a field.
694 HRESULT hr = S_OK;
695
696 _ASSERTE((bExtra == 0) || (bExtra == 1));
697 _ASSERTE(NumItems(pCols) >= pTable->m_cCols);
698
699 bExtra = 0;//<TODO>@FUTURE: save in schema header. until then use 0.</TODO>
700
701 iOffset = 0;
702
703 pTemplate = GetTableDefTemplate(ixTbl);
704
705 PREFIX_ASSUME(pTemplate->m_pColDefs != NULL);
706
707 // For each column in the table...
708 for (ULONG ixCol = 0; ixCol < pTable->m_cCols; ++ixCol)
709 {
710 // Initialize from the template values (type, maybe offset, size).
711 pCols[ixCol] = pTemplate->m_pColDefs[ixCol];
712
713 // Is the field a RID into a table?
714 if (pCols[ixCol].m_Type <= iRidMax)
715 {
716 iSize = cbRID(Schema.m_cRecs[pCols[ixCol].m_Type] << bExtra);
717 }
718 else
719 // Is the field a coded token?
720 if (pCols[ixCol].m_Type <= iCodedTokenMax)
721 {
722 ULONG iCdTkn = pCols[ixCol].m_Type - iCodedToken;
723 ULONG cRecs = 0;
724
725 _ASSERTE(iCdTkn < lengthof(g_CodedTokens));
726 CCodedTokenDef const *pCTD = &g_CodedTokens[iCdTkn];
727
728 // Iterate the token list of this coded token.
729 for (ULONG ixToken=0; ixToken<pCTD->m_cTokens; ++ixToken)
730 { // Ignore string tokens.
731 if (pCTD->m_pTokens[ixToken] != mdtString)
732 {
733 // Get the table for the token.
734 ULONG nTokenTable = CMiniMdRW::GetTableForToken(pCTD->m_pTokens[ixToken]);
735 _ASSERTE(nTokenTable < TBL_COUNT);
736 // If largest token seen so far, remember it.
737 if (Schema.m_cRecs[nTokenTable] > cRecs)
738 cRecs = Schema.m_cRecs[nTokenTable];
739 }
740 }
741
742 iSize = cbRID(cRecs << (bExtra + m_cb[pCTD->m_cTokens]));
743
744 }
745 else
746 { // Fixed type.
747 switch (pCols[ixCol].m_Type)
748 {
749 case iBYTE:
750 iSize = 1;
751 _ASSERTE(pCols[ixCol].m_cbColumn == iSize);
752 _ASSERTE(pCols[ixCol].m_oColumn == iOffset);
753 break;
754 case iSHORT:
755 case iUSHORT:
756 iSize = 2;
757 _ASSERTE(pCols[ixCol].m_cbColumn == iSize);
758 _ASSERTE(pCols[ixCol].m_oColumn == iOffset);
759 break;
760 case iLONG:
761 case iULONG:
762 iSize = 4;
763 _ASSERTE(pCols[ixCol].m_cbColumn == iSize);
764 _ASSERTE(pCols[ixCol].m_oColumn == iOffset);
765 break;
766 case iSTRING:
767 iSize = (Schema.m_heaps & CMiniMdSchema::HEAP_STRING_4) ? 4 : 2;
768 break;
769 case iGUID:
770 iSize = (Schema.m_heaps & CMiniMdSchema::HEAP_GUID_4) ? 4 : 2;
771 break;
772 case iBLOB:
773 iSize = (Schema.m_heaps & CMiniMdSchema::HEAP_BLOB_4) ? 4 : 2;
774 break;
775 default:
776 _ASSERTE(!"Unexpected schema type");
777 iSize = 0;
778 break;
779 }
780 }
781
782 // Now save the size and offset.
783 pCols[ixCol].m_oColumn = iOffset;
784 pCols[ixCol].m_cbColumn = iSize;
785
786 // Align to 2 bytes.
787 iSize += iSize & 1;
788
789 iOffset += iSize;
790 }
791 // Record size of entire record.
792 pTable->m_cbRec = iOffset;
793
794 _ASSERTE(pTable->m_pColDefs != NULL);
795
796 // Can we write to the memory
797 if (!fUsePointers)
798 {
799 memcpy(pTable->m_pColDefs, pCols, sizeof(CMiniColDef)*pTable->m_cCols);
800 }
801 else
802 {
803 // We'll need to have pTable->m_pColDefs point to some data instead
804 hr = SetNewColumnDefinition(pTable, pCols, ixTbl);
805 }
806 // If no key, set to a distinct value.
807 if (pTable->m_iKey >= pTable->m_cCols)
808 pTable->m_iKey = (BYTE) -1;
809
810 return hr;
811} // CMiniMdBase::InitColsForTable
812
813//*****************************************************************************
814// Place a new Column Definition into the metadata.
815//*****************************************************************************
816HRESULT
817CMiniMdBase::SetNewColumnDefinition(
818 CMiniTableDef *pTable,
819 CMiniColDef *pCols,
820 DWORD ixTbl)
821{
822 // Look up the global cache to see if we can use a cached copy
823 if (UsesAllocatedMemory(pCols) ||
824 !FindSharedColDefs(pTable, pCols, ixTbl))
825 {
826 // See if we've already allocated memory for this item
827
828 if (!UsesAllocatedMemory(pTable->m_pColDefs))
829 {
830 // We don't have this column definition cached. Allocate new memory for it.
831 // Notice, we allocate one more byte than necessary, so we can 'mark' this chunk of memory
832 // as allocated so we can free it later.
833
834 BYTE *newMemory = new (nothrow) BYTE[(sizeof(CMiniColDef)*pTable->m_cCols)+1];
835
836 if (newMemory == NULL)
837 return E_OUTOFMEMORY;
838
839 // Mark the first byte in this as with the "allocated memory marker"
840 *newMemory = ALLOCATED_MEMORY_MARKER;
841
842 // Have the pointer point to the first Column Descriptor
843 pTable->m_pColDefs = BYTEARRAY_TO_COLDES(newMemory);
844 }
845
846 memcpy(pTable->m_pColDefs, pCols, sizeof(CMiniColDef)*pTable->m_cCols);
847 }
848
849 return S_OK;
850} // CMiniMdBase::SetNewColumnDefinition
851
852
853//*****************************************************************************
854// Get the count of records in a table. Virtual.
855//*****************************************************************************
856ULONG
857CMiniMdBase::GetCountRecs(
858 ULONG ixTbl)
859{
860 _ASSERTE(ixTbl < TBL_COUNT);
861 return m_Schema.m_cRecs[ixTbl];
862} // CMiniMdBase::GetCountRecs
863
864//*****************************************************************************
865// Search a table for multiple (adjacent) rows containing the given
866// key value. EG, InterfaceImpls all point back to the implementing class.
867//*****************************************************************************
868__checkReturn
869HRESULT
870CMiniMdBase::SearchTableForMultipleRows(
871 ULONG ixTbl, // Table to search.
872 CMiniColDef sColumn, // Sorted key column, containing search value.
873 ULONG ulTarget, // Target for search.
874 RID *pEnd, // [OPTIONAL, OUT]
875 RID *pFoundRid) // First RID found, or 0.
876{
877 HRESULT hr;
878 ULONG ridBegin; // RID of first entry.
879 ULONG ridEnd; // RID of first entry past last entry.
880
881 // Search for any entry in the table.
882 IfFailRet(vSearchTable(ixTbl, sColumn, ulTarget, &ridBegin));
883
884 // If nothing found, return invalid RID.
885 if (ridBegin == 0)
886 {
887 if (pEnd != NULL)
888 {
889 *pEnd = 0;
890 }
891 *pFoundRid = 0;
892 return S_OK;
893 }
894
895 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
896 // If you change the rows touched while searching, please update
897 // CMiniMdRW::GetHotMetadataTokensSearchAware
898 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
899
900
901 // End will be at least one larger than found record.
902 ridEnd = ridBegin + 1;
903
904 // Search back to start of group.
905 for (;;)
906 {
907 void *pRow;
908 if (ridBegin <= 1)
909 {
910 break;
911 }
912 IfFailRet(vGetRow(ixTbl, ridBegin-1, &pRow));
913 if (getIX(pRow, sColumn) != ulTarget)
914 {
915 break;
916 }
917 --ridBegin;
918 }
919
920 // If desired, search forward to end of group.
921 if (pEnd != NULL)
922 {
923 for (;;)
924 {
925 void *pRow;
926 if (ridEnd > GetCountRecs(ixTbl))
927 {
928 break;
929 }
930 IfFailRet(vGetRow(ixTbl, ridEnd, &pRow));
931 if (getIX(pRow, sColumn) != ulTarget)
932 {
933 break;
934 }
935 ++ridEnd;
936 }
937 *pEnd = ridEnd;
938 }
939
940 *pFoundRid = ridBegin;
941 return S_OK;
942} // CMiniMdBase::SearchTableForMultipleRows
943
944
945#if BIGENDIAN
946// Endian Swaps the passed in blob representing a constant into the passed in StgPool
947HRESULT
948CMiniMdBase::SwapConstant(
949 const void *pBlobValue, // Original Value pointer
950 DWORD dwType, // Type of the constant
951 void *pConstant, // [Out] Location to store constant into
952 ULONG ValueLength) // [In] Length of constant
953{
954 HRESULT hr = NOERROR;
955
956 switch (dwType)
957 {
958 case ELEMENT_TYPE_BOOLEAN:
959 case ELEMENT_TYPE_I1:
960 case ELEMENT_TYPE_U1:
961 case ELEMENT_TYPE_VOID:
962 // Just return the value
963 *(BYTE *)pConstant = *(BYTE *)pBlobValue;
964 return NOERROR;
965
966 case ELEMENT_TYPE_I2:
967 case ELEMENT_TYPE_U2:
968 case ELEMENT_TYPE_CHAR:
969 _ASSERTE(ValueLength == 2);
970 *(SHORT *)pConstant = GET_UNALIGNED_VAL16(pBlobValue);
971 break;
972 case ELEMENT_TYPE_CLASS:
973 case ELEMENT_TYPE_I4:
974 case ELEMENT_TYPE_U4:
975 _ASSERTE(ValueLength == 4);
976 *(__int32 *)pConstant = GET_UNALIGNED_VAL32(pBlobValue);
977 break;
978 case ELEMENT_TYPE_R4:
979 {
980 __int32 Value = GET_UNALIGNED_VAL32(pBlobValue);
981 *(float *)pConstant = (float &)Value;
982 }
983 break;
984
985 case ELEMENT_TYPE_R8:
986 {
987 __int64 Value = GET_UNALIGNED_VAL64(pBlobValue);
988 *(double *)pConstant = (double &) Value;
989 }
990 break;
991
992 case ELEMENT_TYPE_I8:
993 case ELEMENT_TYPE_U8:
994 _ASSERTE(ValueLength == 8);
995 *(__int64 *)pConstant = GET_UNALIGNED_VAL64(pBlobValue);
996 break;
997 case ELEMENT_TYPE_STRING:
998 memcpy(pConstant, pBlobValue, ValueLength);
999 SwapStringLength((WCHAR *)pConstant, (ValueLength)/sizeof(WCHAR));
1000 break;
1001 default:
1002 _ASSERTE(!"BAD TYPE!");
1003 return E_INVALIDARG;
1004 break;
1005 }
1006 return hr;
1007} // CMiniMdBase::SwapConstant
1008#endif //BIGENDIAN
1009
1010//*****************************************************************************
1011// It is non-trivial to sort propertymap. VB is generating properties in
1012// non-sorted order!!!
1013//*****************************************************************************
1014HRESULT
1015CMiniMdBase::FindPropertyMapFor(
1016 RID ridParent,
1017 RID *pFoundRid)
1018{
1019 HRESULT hr;
1020 ULONG i;
1021 ULONG iCount;
1022 void *pRec;
1023 RID rid;
1024
1025 // If the table is sorted, use binary search. However we can only trust
1026 // the sorted bit if we have verified it (see definition in MetaModel.h)
1027 if (IsVerified() && m_Schema.IsSorted(TBL_PropertyMap))
1028 {
1029 return vSearchTable(TBL_PropertyMap,
1030 _COLDEF(PropertyMap,Parent),
1031 ridParent,
1032 pFoundRid);
1033 }
1034 else
1035 {
1036 iCount = GetCountRecs(TBL_PropertyMap);
1037
1038 // loop through all LocalVar
1039 for (i = 1; i <= iCount; i++)
1040 {
1041 IfFailRet(vGetRow(TBL_PropertyMap, i, &pRec));
1042
1043 // linear search for propertymap record
1044 rid = getIX(pRec, _COLDEF(PropertyMap,Parent));
1045 if (rid == ridParent)
1046 {
1047 *pFoundRid = i;
1048 return S_OK;
1049 }
1050 }
1051
1052 *pFoundRid = 0;
1053 return S_OK;
1054 }
1055
1056} // CMiniMdBase::FindPropertyMapFor
1057
1058
1059//*****************************************************************************
1060// It is non-trivial to sort eventmap. VB is generating events in
1061// non-sorted order!!!
1062//*****************************************************************************
1063__checkReturn
1064HRESULT
1065CMiniMdBase::FindEventMapFor(
1066 RID ridParent,
1067 RID *pFoundRid)
1068{
1069 HRESULT hr;
1070 ULONG i;
1071 ULONG iCount;
1072 void *pRec;
1073 RID rid;
1074
1075 // If the table is sorted, use binary search. However we can only trust
1076 // the sorted bit if we have verified it (see definition in MetaModel.h)
1077 if (IsVerified() && m_Schema.IsSorted(TBL_EventMap))
1078 {
1079 return vSearchTable(TBL_EventMap,
1080 _COLDEF(EventMap,Parent),
1081 ridParent,
1082 pFoundRid);
1083 }
1084 else
1085 {
1086 iCount = GetCountRecs(TBL_EventMap);
1087
1088 // loop through all LocalVar
1089 for (i = 1; i <= iCount; i++)
1090 {
1091 IfFailRet(vGetRow(TBL_EventMap, i, &pRec));
1092
1093 // linear search for propertymap record
1094 rid = getIX(pRec, _COLDEF(EventMap,Parent));
1095 if (rid == ridParent)
1096 {
1097 *pFoundRid = i;
1098 return S_OK;
1099 }
1100 }
1101
1102 *pFoundRid = 0;
1103 return S_OK;
1104 }
1105} // CMiniMdBase::FindEventMapFor
1106
1107
1108//*****************************************************************************
1109// Search for a custom value with a given type.
1110//*****************************************************************************
1111__checkReturn
1112HRESULT
1113CMiniMdBase::FindCustomAttributeFor(
1114 RID rid, // The object's rid.
1115 mdToken tkObj, // The object's type.
1116 mdToken tkType, // Type of custom value.
1117 RID *pFoundRid) // RID of custom value, or 0.
1118{
1119 HRESULT hr;
1120 int ixFound; // index of some custom value row.
1121 ULONG ulTarget = encodeToken(rid,tkObj,mdtHasCustomAttribute,lengthof(mdtHasCustomAttribute)); // encoded token representing target.
1122 ULONG ixCur; // Current row being examined.
1123 mdToken tkFound; // Type of some custom value row.
1124 void *pCur; // A custom value entry.
1125
1126 // Search for any entry in CustomAttribute table. Convert to RID.
1127 IfFailRet(vSearchTable(TBL_CustomAttribute, _COLDEF(CustomAttribute,Parent), ulTarget, (RID *)&ixFound));
1128 if (ixFound == 0)
1129 {
1130 *pFoundRid = 0;
1131 return S_OK;
1132 }
1133
1134 // Found an entry that matches the item. Could be anywhere in a range of
1135 // custom values for the item, somewhat at random. Search for a match
1136 // on name. On entry to the first loop, we know the object is the desired
1137 // one, so the object test is at the bottom.
1138 ixCur = ixFound;
1139 IfFailRet(vGetRow(TBL_CustomAttribute, ixCur, &pCur));
1140 for(;;)
1141 {
1142 // Test the type of the current row.
1143 tkFound = getIX(pCur, _COLDEF(CustomAttribute,Type));
1144 tkFound = decodeToken(tkFound, mdtCustomAttributeType, lengthof(mdtCustomAttributeType));
1145 if (tkFound == tkType)
1146 {
1147 *pFoundRid = ixCur;
1148 return S_OK;
1149 }
1150 // Was this the last row of the CustomAttribute table?
1151 if (ixCur == GetCountRecs(TBL_CustomAttribute))
1152 break;
1153 // No match, more rows, try for the next row.
1154 ++ixCur;
1155 // Get the row and see if it is for the same object.
1156 IfFailRet(vGetRow(TBL_CustomAttribute, ixCur, &pCur));
1157 if (getIX(pCur, _COLDEF(CustomAttribute,Parent)) != ulTarget)
1158 break;
1159 }
1160 // Didn't find the name looking up. Try looking down.
1161 ixCur = ixFound - 1;
1162 for(;;)
1163 {
1164 // Run out of table yet?
1165 if (ixCur == 0)
1166 break;
1167 // Get the row and see if it is for the same object.
1168 IfFailRet(vGetRow(TBL_CustomAttribute, ixCur, &pCur));
1169 // still looking at the same object?
1170 if (getIX(pCur, _COLDEF(CustomAttribute,Parent)) != ulTarget)
1171 break;
1172 // Test the type of the current row.
1173 tkFound = getIX(pCur, _COLDEF(CustomAttribute,Type));
1174 tkFound = decodeToken(tkFound, mdtCustomAttributeType, lengthof(mdtCustomAttributeType));
1175 if (tkFound == tkType)
1176 {
1177 *pFoundRid = ixCur;
1178 return S_OK;
1179 }
1180 // No match, try for the previous row.
1181 --ixCur;
1182 }
1183 // Didn't find anything.
1184 *pFoundRid = 0;
1185 return S_OK;
1186} // CMiniMdBase::FindCustomAttributeFor
1187
1188//*****************************************************************************
1189// See if we can find a globally shared Column Def Array for this table
1190//*****************************************************************************
1191BOOL
1192CMiniMdBase::FindSharedColDefs(
1193 CMiniTableDef *pTable,
1194 CMiniColDef *pColsToMatch,
1195 DWORD ixTbl)
1196{
1197 // The majority of the time, m_pColDefs will point to the correct Column Definition Array.
1198 if (!memcmp(pTable->m_pColDefs, pColsToMatch, sizeof(CMiniColDef)*(pTable->m_cCols)))
1199 return TRUE;
1200
1201 else
1202 {
1203 // m_pColDefs points to a set of Column Def Arrays, with the byte previous to it the number
1204 // of column descriptors that we have.
1205 CMiniColDef *pListOfColumnDefs = BYTEARRAY_TO_COLDES(s_TableColumnDescriptors[ixTbl]);
1206
1207 BYTE nNumColDes = *(s_TableColumnDescriptors[ixTbl]);
1208
1209 // Start at '1' since we already compared the first set of column definitions above.
1210 for (int i = 1; i < nNumColDes; i++)
1211 {
1212 pListOfColumnDefs += pTable->m_cCols;
1213
1214 if (!memcmp(pListOfColumnDefs, pColsToMatch, sizeof(CMiniColDef)*(pTable->m_cCols)))
1215 {
1216 pTable->m_pColDefs = pListOfColumnDefs;
1217 return TRUE;
1218 }
1219 }
1220 }
1221
1222 // We weren't able to find a shared column definition
1223 return FALSE;
1224}// CMiniMdBase::FindSharedColDefs
1225
1226//*****************************************************************************
1227// Determines where the Table Def's Column Definitions used shared memory or
1228// allocated memory
1229//*****************************************************************************
1230BOOL
1231CMiniMdBase::UsesAllocatedMemory(
1232 CMiniColDef *pCols)
1233{
1234 BYTE *pMem = COLDES_TO_BYTEARRAY(pCols);
1235
1236 // If the byte preceding this pointer is -1, then we allocated it and it must be freed
1237 return (*pMem == ALLOCATED_MEMORY_MARKER);
1238}// CMiniMdBase::UsesAllocatedMemory
1239