Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DNMD API to create a new metadata handle and implement IMetaDataDispenser::DefineScope #49

Merged
merged 10 commits into from
Jan 18, 2024
Merged
113 changes: 113 additions & 0 deletions src/dnmd/entry.c
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,119 @@ bool md_create_handle(void const* data, size_t data_len, mdhandle_t* handle)
return true;
}

// Initialize the minimal set of tables required for a valid metadata image.
// Every image must have a row in the Module table
// for module identity information
// and a row in the TypeDef table for the global type.
static bool initialize_minimal_table_rows(mdcxt_t* cxt)
{
// Add the Module row for module identity
mdcursor_t module_cursor;
if (!md_append_row(cxt, mdtid_Module, &module_cursor))
return false;

// Set the Generation to 0
uint32_t generation = 0;
if (1 != md_set_column_value_as_constant(module_cursor, mdtModule_Generation, 1, &generation))
return false;

// Use the 0 index to specify the NULL guid as the guids for the image.
uint32_t guid_heap_offset = 0;
if (1 != set_column_value_as_heap_offset(module_cursor, mdtModule_Mvid, 1, &guid_heap_offset)
|| 1 != set_column_value_as_heap_offset(module_cursor, mdtModule_EncBaseId, 1, &guid_heap_offset)
|| 1 != set_column_value_as_heap_offset(module_cursor, mdtModule_EncId, 1, &guid_heap_offset))
{
return false;
}

char const* name = "";
if (1 != md_set_column_value_as_utf8(module_cursor, mdtModule_Name, 1, &name))
return false;

// Mark that we're done adding the Module row.
md_commit_row_add(module_cursor);

// Add a row for the global <Module> type.
mdcursor_t global_type_cursor;
if (!md_append_row(cxt, mdtid_TypeDef, &global_type_cursor))
return false;

uint32_t flags = 0;
if (1 != md_set_column_value_as_constant(global_type_cursor, mdtTypeDef_Flags, 1, &flags))
return false;

char const* global_type_name = "<Module>"; // Defined in ECMA-335 II.10.8
if (1 != md_set_column_value_as_utf8(global_type_cursor, mdtTypeDef_TypeName, 1, &global_type_name))
return false;

char const* namespace = "";
if (1 != md_set_column_value_as_utf8(global_type_cursor, mdtTypeDef_TypeNamespace, 1, &namespace))
return false;

mdToken nil_typedef = CreateTokenType(mdtTypeDef);
if (1 != md_set_column_value_as_token(global_type_cursor, mdtTypeDef_Extends, 1, &nil_typedef))
return false;

// Mark that we're done adding the TypeDef row.
md_commit_row_add(global_type_cursor);

return true;
}

mdhandle_t md_create_new_handle()
{
mdcxt_t cxt;

memset(&cxt, 0, sizeof(mdcxt_t));
cxt.magic = MDLIB_MAGIC_NUMBER;
cxt.context_flags = mdc_none;
cxt.major_ver = 1;
cxt.minor_ver = 1;
cxt.flags = 0;
cxt.version = "v4.0.30319";
cxt.editor = NULL;
cxt.mem = NULL;

// Allocate and initialize a full context
// with the correctly-sized trailing memory.
mdcxt_t* pcxt = allocate_full_context(&cxt);
if (pcxt == NULL)
return NULL;

if (!initialize_minimal_table_rows(pcxt))
{
free(pcxt);
return NULL;
}

return pcxt;
}

jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
#ifdef DNMD_PORTABLE_PDB
mdhandle_t md_create_new_pdb_handle()
{
mdcxt_t cxt;

memset(&cxt, 0, sizeof(mdcxt_t));
cxt.magic = MDLIB_MAGIC_NUMBER;
cxt.context_flags = mdc_none;
cxt.major_ver = 1;
cxt.minor_ver = 1;
cxt.flags = 0;
cxt.version = "PDB v1.0";
cxt.editor = NULL;
cxt.mem = NULL;

// Allocate and initialize a full context
// with the correctly-sized trailing memory.
mdcxt_t* pcxt = allocate_full_context(&cxt);
if (pcxt == NULL)
return NULL;

return pcxt;
}
#endif
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved

bool md_apply_delta(mdhandle_t handle, void const* data, size_t data_len)
{
mdcxt_t* base = extract_mdcxt(handle);
Expand Down
17 changes: 17 additions & 0 deletions src/inc/dnmd.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,21 @@ typedef void* mdhandle_t;
// If modifications are made, the data will not be updated in place.
bool md_create_handle(void const* data, size_t data_len, mdhandle_t* handle);

// Create a new metadata handle for a new image.
// Returns a handle for the new image, or NULL if the handle could not be created.
// The image will always be in the v1.1 ECMA-355 metadata format,
// use the "v4.0.30319" version string,
// and have an MVID of all zeros.
mdhandle_t md_create_new_handle();

#ifdef DNMD_PORTABLE_PDB
// Create a new metadata handle for a new Portable PDB image.
// Returns a handle for the new image, or NULL if the handle could not be created.
// The image will always be in the v1.1 metadata format
// and use the "PDB v1.0" version string.
mdhandle_t md_create_new_pdb_handle();
#endif
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved

// Apply delta data to the current metadata.
bool md_apply_delta(mdhandle_t handle, void const* data, size_t data_len);

Expand Down Expand Up @@ -528,6 +543,8 @@ void md_commit_row_add(mdcursor_t row);
// Add a user string to the #US heap.
mduserstringcursor_t md_add_userstring_to_heap(mdhandle_t handle, char16_t const* userstring);

// Write the metadata represented by the handle to the supplied buffer.
// The metadata is always written with the v2.0 table schema.
bool md_write_to_buffer(mdhandle_t handle, uint8_t* buffer, size_t* len);
#ifdef __cplusplus
}
Expand Down
49 changes: 44 additions & 5 deletions src/interfaces/dispenser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,50 @@ namespace
REFIID riid,
IUnknown** ppIUnk)
{
UNREFERENCED_PARAMETER(rclsid);
UNREFERENCED_PARAMETER(dwCreateFlags);
UNREFERENCED_PARAMETER(riid);
UNREFERENCED_PARAMETER(ppIUnk);
return E_NOTIMPL;
if (rclsid != CLSID_CLR_v2_MetaData)
{
// DNMD::Interfaces only creating v2 metadata images.
return CLDB_E_FILE_OLDVER;
}

if (dwCreateFlags != 0)
{
return E_INVALIDARG;
}

mdhandle_ptr md_ptr { md_create_new_handle() };
if (md_ptr == nullptr)
return E_OUTOFMEMORY;

// Initialize the MVID of the new image.
mdcursor_t moduleCursor;
if (!md_token_to_cursor(md_ptr.get(), TokenFromRid(1, mdtModule), &moduleCursor))
return E_FAIL;

mdguid_t mvid;
HRESULT hr = PAL_CoCreateGuid(reinterpret_cast<GUID*>(&mvid));
if (FAILED(hr))
return hr;

if (1 != md_set_column_value_as_guid(moduleCursor, mdtModule_Mvid, 1, &mvid))
return E_OUTOFMEMORY;

dncp::com_ptr<ControllingIUnknown> obj;
obj.Attach(new (std::nothrow) ControllingIUnknown());
if (obj == nullptr)
return E_OUTOFMEMORY;

try
{
mdhandle_view handle_view{ obj->CreateAndAddTearOff<DNMDOwner>(std::move(md_ptr)) };
(void)obj->CreateAndAddTearOff<MetadataImportRO>(std::move(handle_view));
}
catch(std::bad_alloc const&)
{
return E_OUTOFMEMORY;
}

return obj->QueryInterface(riid, (void**)ppIUnk);
}

STDMETHOD(OpenScope)(
Expand Down
7 changes: 7 additions & 0 deletions src/interfaces/dnmdowner.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,13 @@ class DNMDOwner final : public TearOffBase<IDNMDOwner>
}

public:
DNMDOwner(IUnknown* controllingUnknown, mdhandle_ptr md_ptr)
: TearOffBase(controllingUnknown)
, _handle{ std::move(md_ptr) }
, _malloc_to_free{ nullptr }
, _cotaskmem_to_free{ nullptr }
{ }

DNMDOwner(IUnknown* controllingUnknown, mdhandle_ptr md_ptr, malloc_ptr<void> mallocMem, dncp::cotaskmem_ptr<void> cotaskmemMem)
: TearOffBase(controllingUnknown)
, _handle{ std::move(md_ptr) }
Expand Down
3 changes: 3 additions & 0 deletions src/interfaces/iids.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,8 @@ MIDL_DEFINE_GUID(IID_IMetaDataEmit2, 0xf5dd9950, 0xf693, 0x42e6, 0x83, 0xe, 0x7b
// Define the ISymUnmanaged* IIDs here - corsym.h provides the declaration.
MIDL_DEFINE_GUID(IID_ISymUnmanagedBinder, 0xaa544d42, 0x28cb, 0x11d3, 0xbd, 0x22, 0x00, 0x00, 0xf8, 0x08, 0x49, 0xbd);

// Define option IIDs here - cor.h provides the declaration.
MIDL_DEFINE_GUID(CLSID_CLR_v2_MetaData, 0xefea471a, 0x44fd, 0x4862, 0x92, 0x92, 0xc, 0x58, 0xd4, 0x6e, 0x1f, 0x3a);

// Define an IID for our own marker interface
MIDL_DEFINE_GUID(IID_IDNMDOwner, 0x250ebc02, 0x1a92, 0x4638, 0xaa, 0x6c, 0x3d, 0x0f, 0x98, 0xb3, 0xa6, 0xfb);