Fix broken new lines (#23979)
authorGergely Kalapos <gergo@kalapos.net>
Sun, 14 Apr 2019 17:16:24 +0000 (19:16 +0200)
committerJan Kotas <jkotas@microsoft.com>
Sun, 14 Apr 2019 17:16:24 +0000 (10:16 -0700)
These files don't render correctly on github due to broken new lines - fixing it. Only new line characters replaced, nothing else touched.

Documentation/Profiling/davbr-blog-archive/samples/PlugInToYourProfiler.cpp
Documentation/Profiling/davbr-blog-archive/samples/sigparse.cpp

index 81471bb..561f591 100644 (file)
@@ -1 +1,477 @@
-// This blog post originally appeared on David Broman's blog on 10/13/2005\r\r#include "SigFormat.cpp"\r \r \r // ---------------------------------------------------------------------\r // ---------------------------------------------------------------------\r // This file does not compile on its own. It contains snippets of code you can add\r // to a working profiler, so that your profiler will invoke instances of the SigFormat\r // object to parse and pretty-print all the types in all modules as they're loaded.\r //\r // The functions are ordered from callees to callers (so no forward declarations are\r // necessary). If you prefer a top-down approach to learning code, then start\r // at the bottom of the file.\r // ---------------------------------------------------------------------\r // ---------------------------------------------------------------------\r \r \r // ****************************************************************\r // HELPERS TO READ THROUGH METADATA, FIND SIGNATURES, AND INVOKE THE PARSER\r // ****************************************************************\r \r // Simple wrapper to create an instance of SigFormat and invoke it\rHRESULT DoParse(sig_byte * sig, ULONG cbSig)\r{\r    SigFormat sf;\r    HRESULT hr;\r    bool fRet = sf.Parse(sig, cbSig);\r    if (!fRet)\r    {\r        hr = E_FAIL;\r        goto Error;\r    }\r\r    hr = S_OK;\r\r    Cleanup:\r    return hr;\r\r    Error:\r    goto Cleanup;\r}\r\r // Takes an mdProperty, prints an intro line, then invokes the parser / printer\rHRESULT PrintProperty(ModuleID moduleID, IMetaDataImport* pMDImport, LPCWSTR wszClassName, mdProperty md)\r{\r    HRESULT hr;\r    mdTypeDef td;\r    WCHAR wszName[500];\r    ULONG cchName;\r    PCCOR_SIGNATURE sigMember;\r    ULONG cbSigMember;\r    DWORD dwAttr;\r    DWORD dwCPlusTypeFlag;\r    UVCP_CONSTANT pValue;\r    ULONG cchValue;\r    mdMethodDef mdSetter;\r    mdMethodDef mdGetter;\r    mdMethodDef aOtherMethods[100];\r    ULONG cOtherMethods;\r\r    hr = pMDImport->GetPropertyProps(md, // The member for which to get props. \r                                     &td, // Put member's class here. \r                                     wszName, // Put member's name here. \r                                     dimensionof(wszName), // Size of szMember buffer in wide chars. \r                                     &cchName, // Put actual size here \r                                     &dwAttr, // Put flags here. \r                                     &sigMember, // [OUT] point to the blob value of meta data \r                                     &cbSigMember, // [OUT] actual size of signature blob \r                                     &dwCPlusTypeFlag, // [OUT] flag for value type. selected ELEMENT_TYPE_* \r                                     &pValue, // [OUT] constant value \r                                     &cchValue,\r                                     &mdSetter, // [OUT] setter method of the property \r                                     &mdGetter, // [OUT] getter method of the property \r                                     aOtherMethods, // [OUT] other method of the property \r                                     dimensionof(aOtherMethods), // [IN] size of rmdOtherMethod\r                                     &cOtherMethods); // [OUT] total number of other method of this property\r    if (FAILED(hr))\r    {\r        goto Error;\r    }\r\r    printf("\n%S.%S (0x%x)\n", wszClassName, wszName, md);\r    DoParse((sig_byte *) sigMember, cbSigMember);\r\r    hr = S_OK;\r\r    Cleanup:\r    return hr;\r\r    Error:\r    goto Cleanup;\r\r}\r\r\r // Takes a field token, prints an intro line, then invokes the parser / printer\rHRESULT PrintField(ModuleID moduleID, IMetaDataImport* pMDImport, LPCWSTR wszClassName, mdToken md)\r{\r    HRESULT hr;\r    mdTypeDef td;\r    WCHAR wszName[500];\r    ULONG cchName;\r    PCCOR_SIGNATURE sigMember;\r    ULONG cbSigMember;\r    DWORD dwAttr;\r    DWORD dwCPlusTypeFlag;\r    UVCP_CONSTANT pValue;\r    ULONG cchValue;\r\r    hr = pMDImport->GetFieldProps(md, // The member for which to get props. \r                                  &td, // Put member's class here. \r                                  wszName, // Put member's name here. \r                                  dimensionof(wszName), // Size of szMember buffer in wide chars. \r                                  &cchName, // Put actual size here \r                                  &dwAttr, // Put flags here. \r                                  &sigMember, // [OUT] point to the blob value of meta data \r                                  &cbSigMember, // [OUT] actual size of signature blob \r                                  &dwCPlusTypeFlag, // [OUT] flag for value type. selected ELEMENT_TYPE_* \r                                  &pValue, // [OUT] constant value \r                                  &cchValue); // [OUT] size of constant string in chars, 0 for non-strings.\r    if (FAILED(hr))\r    {\r        goto Error;\r    }\r\r    printf("\n%S.%S (0x%x)\n", wszClassName, wszName, md);\r    DoParse((sig_byte *) sigMember, cbSigMember);\r\r    hr = S_OK;\r\r    Cleanup:\r    return hr;\r\r    Error:\r    goto Cleanup;\r\r}\r\r // Takes an mdMethodDef, prints an intro line, then invokes the parser / printer on its signature and its locals\rHRESULT PrintMethodDef(ModuleID moduleID, IMetaDataImport* pMDImport, LPCWSTR wszClassName, mdMethodDef md)\r{\r    HRESULT hr;\r    mdTypeDef td;\r    WCHAR wszMethod[500];\r    ULONG cchMethod;\r    DWORD dwAttr;\r    PCCOR_SIGNATURE sigParam;\r    PCCOR_SIGNATURE sigLocal;\r    ULONG cbSigParam;\r    ULONG cbSigLocal;\r    ULONG ulCodeRVA;\r    DWORD dwImplFlags;\r    BOOL fMore;\r    LPCBYTE pMethodHeader = NULL;\r    ULONG cbMethodSize;\r    IMAGE_COR_ILMETHOD_TINY* pimt = NULL;\r    IMAGE_COR_ILMETHOD_FAT* pimf = NULL;\r\r    hr = pMDImport->GetMethodProps(md, // The method for which to get props. \r                                   &td, // Put method's class here. \r                                   wszMethod, // Put method's name here. \r                                   dimensionof(wszMethod), // Size of szMethod buffer in wide chars. \r                                   &cchMethod, // Put actual size here \r                                   &dwAttr, // Put flags here. \r                                   &sigParam, // [OUT] point to the blob value of meta data \r                                   &cbSigParam, // [OUT] actual size of signature blob \r                                   &ulCodeRVA, // [OUT] codeRVA \r                                   &dwImplFlags); // [OUT] Impl. Flags \r    if (FAILED(hr))\r    {\r        goto Error;\r    }\r\r    printf("\n%S.%S (0x%x)\n", wszClassName, wszMethod, md);\r\r     // Method prototype signature parse\r    DoParse((sig_byte *) sigParam, cbSigParam);\r\r     // Method locals signature parse\r    hr = g_pProfilerInfo->GetILFunctionBody(moduleID,\r                                            md,\r                                            &pMethodHeader,\r                                            &cbMethodSize);\r    if (FAILED(hr))\r    {\r        goto EndLocal;\r    }\r\r    // The following odd-looking lines of code decode the method header, ensure\r    // it is in a format that contains local variables, and then grabs the local\r    // variable signature out of the header.\r\r    pimt = (IMAGE_COR_ILMETHOD_TINY*) pMethodHeader;\r    if ((pimt->Flags_CodeSize & (CorILMethod_FormatMask >> 1)) != CorILMethod_FatFormat)\r    {\r        goto EndLocal;\r    }\r\r    pimf = (IMAGE_COR_ILMETHOD_FAT*) pMethodHeader;\r    if (pimf->LocalVarSigTok == 0)\r    {\r        goto EndLocal;\r    }\r\r    hr = pMDImport->GetSigFromToken(pimf->LocalVarSigTok,\r                                    &sigLocal,\r                                    &cbSigLocal);\r\r    DoParse((sig_byte *) sigLocal, cbSigLocal);\r\r    EndLocal:\r\r    hr = S_OK;\r\r    Cleanup:\r    return hr;\r\r    Error:\r    goto Cleanup;\r}\r\r\r // Simple helper to print an intro line for a class\rvoid PrintHeader(LPCWSTR wszClassName, mdTypeDef td, LPCSTR szCategory)\r{\r    printf("\n--------------------------------------------\n");\r    printf("%S (0x%x):\t%s\n", wszClassName, td, szCategory);\r    printf("--------------------------------------------\n\n");\r}\r\r\r // Combines above functions to print the methods, properties, and fields of a class\rHRESULT PrintTypedef(ModuleID moduleID, IMetaDataImport* pMDImport, mdTypeDef td)\r{\r    HRESULT hr;\r    HCORENUM hEnum = NULL;\r    mdMethodDef aMethods[100];\r    mdFieldDef aFields[100];\r    mdFieldDef aProperties[100];\r    ULONG cMethodDefs;\r    ULONG cFields;\r    ULONG cProperties;\r    ULONG i;\r    WCHAR wszTdName[200];\r    ULONG cchTdName;\r    DWORD dwTypeDefFlags;\r    mdToken tkExtends;\r    BOOL fMore;\r\r    hr = pMDImport->GetTypeDefProps(td, // [IN] TypeDef token for inquiry.\r                                    wszTdName, // [OUT] Put name here.\r                                    dimensionof(wszTdName), // [IN] size of name buffer in wide chars.\r                                    &cchTdName, // [OUT] put size of name (wide chars) here.\r                                    &dwTypeDefFlags, // [OUT] Put flags here.\r                                    &tkExtends); // [OUT] Put base class TypeDef/TypeRef here.\r    if (FAILED(hr))\r    {\r        goto Error;\r    }\r\r    PrintHeader(wszTdName, td, "METHODDEFS");\r    fMore = TRUE;\r    while (fMore)\r    {\r        hr = pMDImport->EnumMethods(&hEnum,\r                                    td, // [IN] TypeDef to scope the enumeration. \r                                    aMethods, // [OUT] Put MethodDefs here. \r                                    dimensionof(aMethods), // [IN] Max MethodDefs to put. \r                                    &cMethodDefs); // [OUT] Put # put here. \r        if (FAILED(hr))\r        {\r            goto Error;\r        }\r\r        if (hr == S_FALSE)\r        {\r            fMore = FALSE;\r        }\r\r        for (i=0; i < cMethodDefs; i++)\r        {\r            hr = PrintMethodDef(moduleID, pMDImport, wszTdName, aMethods[i]);\r            if (FAILED(hr))\r            {\r                 // do you care? If so, do something about this.\r            }\r        }\r    }\r\r    pMDImport->CloseEnum(hEnum);\r    hEnum = NULL;\r\r    PrintHeader(wszTdName, td, "FIELDS");\r    fMore = TRUE;\r    while (fMore)\r    {\r        hr = pMDImport->EnumFields(&hEnum,\r                                   td, \r                                   Fields, \r                                   dimensionof(aFields),\r                                   &cFields);\r\r        if (FAILED(hr))\r        {\r            goto Error;\r        }\r\r        if (hr == S_FALSE)\r        {\r            fMore = FALSE;\r        }\r\r        for (i=0; i < cFields; i++)\r        {\r            hr = PrintField(moduleID, pMDImport, wszTdName, aFields[i]);\r            if (FAILED(hr))\r            {\r                                 // do you care? If so, do something about this.\r            }\r        }\r    }\r\r    pMDImport->CloseEnum(hEnum);\r    hEnum = NULL;\r\r    PrintHeader(wszTdName, td, "PROPERTIES");\r    fMore = TRUE;\r    while (fMore)\r    {\r        hr = pMDImport->EnumProperties(&hEnum,\r                                                                         td, \r                                                                           aProperties, \r                                                                          dimensionof(aProperties),\r                                                                      &cProperties); \r        if (FAILED(hr))\r        {\r            goto Error;\r        }\r\r        if (hr == S_FALSE)\r        {\r            fMore = FALSE;\r        }\r\r        for (i=0; i < cProperties; i++)\r        {\r            hr = PrintProperty(moduleID, pMDImport, wszTdName, aProperties[i]);\r            if (FAILED(hr))\r            {\r                                 // do you care? If so, do something about this.\r            }\r        }\r    }\r\r    pMDImport->CloseEnum(hEnum);\r    hEnum = NULL;\r\r    hr = S_OK;\r\r    Cleanup:\r    if (hEnum != NULL)\r    {\r        pMDImport->CloseEnum(hEnum);\r    }\r    return hr;\r\r    Error:\r    goto Cleanup;\r}\r\r\r // Enumerates the typedefs in a module via the metadata interface, and calls PrintTypedef\r // on each one\rHRESULT PrintMetadata(ModuleID moduleID, IMetaDataImport* pMDImport)\r{\r    HRESULT hr;\r    HCORENUM hEnum = NULL;\r    mdTypeDef aTypeDefs[100];\r    ULONG cTypeDefs;\r    ULONG i;\r    BOOL fMoreTypeDefs = TRUE;\r\r    while (fMoreTypeDefs)\r    {\r        hr = pMDImport->EnumTypeDefs(&hEnum,\r                                                              aTypeDefs,\r                                                             dimensionof(aTypeDefs),\r                                                                &cTypeDefs);\r        if (FAILED(hr))\r        {\r            goto Error;\r        }\r\r        if (hr == S_FALSE)\r        {\r            fMoreTypeDefs = FALSE;\r        }\r\r        for (i=0; i < cTypeDefs; i++)\r        {\r            hr = PrintTypedef(moduleID, pMDImport, aTypeDefs[i]);\r            if (FAILED(hr))\r            {\r                              // do you care? If so, do something about this.\r            }\r        }\r    }\r\r    hr = S_OK;\r\r    Cleanup:\r    if (hEnum != NULL)\r    {\r        pMDImport->CloseEnum(hEnum);\r    }\r    return hr;\r\r    Error:\r    goto Cleanup;\r}\r\r\r // ****************************************************************\r // Add this to your profiler's ICorProfilerCallback2::ModuleLoadFinished implementation.\r // It is assumed your copy of the ICorProfilerInfo2 interface may be accessed via\r // g_pProfilerInfo. Change the code to fit your profiler as appropriate.\r // ****************************************************************\r //\r // As a module gets loaded, this callback implementation initiates the pretty-printer to\r // log all the types to stdout.\rHRESULT CYourProfImpl::ModuleLoadFinished( ModuleID moduleID, HRESULT hrStatus )\r{\r    HRESULT hr;\r    LPCBYTE pbBaseLoadAddr;\r    WCHAR wszName[300];\r    ULONG cchNameIn = dimensionof(wszName);\r    ULONG cchNameOut;\r    AssemblyID assemblyID;\r\r    hr = g_pProfilerInfo->GetModuleInfo(moduleID,\r                                                                        &pbBaseLoadAddr,\r                                                                       cchNameIn,\r                                                                     &cchNameOut,\r                                                                           wszName,\r                                                                       &assemblyID);\r    if (FAILED(hr))\r    {\r        return hr;\r    }\r\r    printf("MODULE LOAD FINISHED: %S\n", wszName);\r\r    IMetaDataImport *pMDImport = NULL;\r    hr = g_pProfilerInfo->GetModuleMetaData(moduleID,\r                                                                         ofRead,\r                                                                                IID_IMetaDataImport,\r                                                                           (IUnknown **)&pMDImport );\r    if (FAILED(hr))\r    {\r        return hr;\r    }\r\r    hr = PrintMetadata(moduleID, pMDImport);\r    if (FAILED(hr))\r    {\r          // Do any error handling as appropriate\r    }\r\r    hr = S_OK;\r\r    Cleanup:\r    return hr;\r\r    Error:\r    goto Cleanup;\r}\r
\ No newline at end of file
+// This blog post originally appeared on David Broman's blog on 10/13/2005
+
+#include "SigFormat.cpp"
+ // ---------------------------------------------------------------------
+ // ---------------------------------------------------------------------
+ // This file does not compile on its own. It contains snippets of code you can add
+ // to a working profiler, so that your profiler will invoke instances of the SigFormat
+ // object to parse and pretty-print all the types in all modules as they're loaded.
+ //
+ // The functions are ordered from callees to callers (so no forward declarations are
+ // necessary). If you prefer a top-down approach to learning code, then start
+ // at the bottom of the file.
+ // ---------------------------------------------------------------------
+ // ---------------------------------------------------------------------
+ // ****************************************************************
+ // HELPERS TO READ THROUGH METADATA, FIND SIGNATURES, AND INVOKE THE PARSER
+ // ****************************************************************
+ // Simple wrapper to create an instance of SigFormat and invoke it
+HRESULT DoParse(sig_byte * sig, ULONG cbSig)
+{
+    SigFormat sf;
+    HRESULT hr;
+    bool fRet = sf.Parse(sig, cbSig);
+    if (!fRet)
+    {
+        hr = E_FAIL;
+        goto Error;
+    }
+
+    hr = S_OK;
+
+    Cleanup:
+    return hr;
+
+    Error:
+    goto Cleanup;
+}
+
+ // Takes an mdProperty, prints an intro line, then invokes the parser / printer
+HRESULT PrintProperty(ModuleID moduleID, IMetaDataImport* pMDImport, LPCWSTR wszClassName, mdProperty md)
+{
+    HRESULT hr;
+    mdTypeDef td;
+    WCHAR wszName[500];
+    ULONG cchName;
+    PCCOR_SIGNATURE sigMember;
+    ULONG cbSigMember;
+    DWORD dwAttr;
+    DWORD dwCPlusTypeFlag;
+    UVCP_CONSTANT pValue;
+    ULONG cchValue;
+    mdMethodDef mdSetter;
+    mdMethodDef mdGetter;
+    mdMethodDef aOtherMethods[100];
+    ULONG cOtherMethods;
+
+    hr = pMDImport->GetPropertyProps(md, // The member for which to get props. 
+                                     &td, // Put member's class here. 
+                                     wszName, // Put member's name here. 
+                                     dimensionof(wszName), // Size of szMember buffer in wide chars. 
+                                     &cchName, // Put actual size here 
+                                     &dwAttr, // Put flags here. 
+                                     &sigMember, // [OUT] point to the blob value of meta data 
+                                     &cbSigMember, // [OUT] actual size of signature blob 
+                                     &dwCPlusTypeFlag, // [OUT] flag for value type. selected ELEMENT_TYPE_* 
+                                     &pValue, // [OUT] constant value 
+                                     &cchValue,
+                                     &mdSetter, // [OUT] setter method of the property 
+                                     &mdGetter, // [OUT] getter method of the property 
+                                     aOtherMethods, // [OUT] other method of the property 
+                                     dimensionof(aOtherMethods), // [IN] size of rmdOtherMethod
+                                     &cOtherMethods); // [OUT] total number of other method of this property
+    if (FAILED(hr))
+    {
+        goto Error;
+    }
+
+    printf("\n%S.%S (0x%x)\n", wszClassName, wszName, md);
+    DoParse((sig_byte *) sigMember, cbSigMember);
+
+    hr = S_OK;
+
+    Cleanup:
+    return hr;
+
+    Error:
+    goto Cleanup;
+
+}
+
+
+ // Takes a field token, prints an intro line, then invokes the parser / printer
+HRESULT PrintField(ModuleID moduleID, IMetaDataImport* pMDImport, LPCWSTR wszClassName, mdToken md)
+{
+    HRESULT hr;
+    mdTypeDef td;
+    WCHAR wszName[500];
+    ULONG cchName;
+    PCCOR_SIGNATURE sigMember;
+    ULONG cbSigMember;
+    DWORD dwAttr;
+    DWORD dwCPlusTypeFlag;
+    UVCP_CONSTANT pValue;
+    ULONG cchValue;
+
+    hr = pMDImport->GetFieldProps(md, // The member for which to get props. 
+                                  &td, // Put member's class here. 
+                                  wszName, // Put member's name here. 
+                                  dimensionof(wszName), // Size of szMember buffer in wide chars. 
+                                  &cchName, // Put actual size here 
+                                  &dwAttr, // Put flags here. 
+                                  &sigMember, // [OUT] point to the blob value of meta data 
+                                  &cbSigMember, // [OUT] actual size of signature blob 
+                                  &dwCPlusTypeFlag, // [OUT] flag for value type. selected ELEMENT_TYPE_* 
+                                  &pValue, // [OUT] constant value 
+                                  &cchValue); // [OUT] size of constant string in chars, 0 for non-strings.
+    if (FAILED(hr))
+    {
+        goto Error;
+    }
+
+    printf("\n%S.%S (0x%x)\n", wszClassName, wszName, md);
+    DoParse((sig_byte *) sigMember, cbSigMember);
+
+    hr = S_OK;
+
+    Cleanup:
+    return hr;
+
+    Error:
+    goto Cleanup;
+
+}
+
+ // Takes an mdMethodDef, prints an intro line, then invokes the parser / printer on its signature and its locals
+HRESULT PrintMethodDef(ModuleID moduleID, IMetaDataImport* pMDImport, LPCWSTR wszClassName, mdMethodDef md)
+{
+    HRESULT hr;
+    mdTypeDef td;
+    WCHAR wszMethod[500];
+    ULONG cchMethod;
+    DWORD dwAttr;
+    PCCOR_SIGNATURE sigParam;
+    PCCOR_SIGNATURE sigLocal;
+    ULONG cbSigParam;
+    ULONG cbSigLocal;
+    ULONG ulCodeRVA;
+    DWORD dwImplFlags;
+    BOOL fMore;
+    LPCBYTE pMethodHeader = NULL;
+    ULONG cbMethodSize;
+    IMAGE_COR_ILMETHOD_TINY* pimt = NULL;
+    IMAGE_COR_ILMETHOD_FAT* pimf = NULL;
+
+    hr = pMDImport->GetMethodProps(md, // The method for which to get props. 
+                                   &td, // Put method's class here. 
+                                   wszMethod, // Put method's name here. 
+                                   dimensionof(wszMethod), // Size of szMethod buffer in wide chars. 
+                                   &cchMethod, // Put actual size here 
+                                   &dwAttr, // Put flags here. 
+                                   &sigParam, // [OUT] point to the blob value of meta data 
+                                   &cbSigParam, // [OUT] actual size of signature blob 
+                                   &ulCodeRVA, // [OUT] codeRVA 
+                                   &dwImplFlags); // [OUT] Impl. Flags 
+    if (FAILED(hr))
+    {
+        goto Error;
+    }
+
+    printf("\n%S.%S (0x%x)\n", wszClassName, wszMethod, md);
+
+     // Method prototype signature parse
+    DoParse((sig_byte *) sigParam, cbSigParam);
+
+     // Method locals signature parse
+    hr = g_pProfilerInfo->GetILFunctionBody(moduleID,
+                                            md,
+                                            &pMethodHeader,
+                                            &cbMethodSize);
+    if (FAILED(hr))
+    {
+        goto EndLocal;
+    }
+
+    // The following odd-looking lines of code decode the method header, ensure
+    // it is in a format that contains local variables, and then grabs the local
+    // variable signature out of the header.
+
+    pimt = (IMAGE_COR_ILMETHOD_TINY*) pMethodHeader;
+    if ((pimt->Flags_CodeSize & (CorILMethod_FormatMask >> 1)) != CorILMethod_FatFormat)
+    {
+        goto EndLocal;
+    }
+
+    pimf = (IMAGE_COR_ILMETHOD_FAT*) pMethodHeader;
+    if (pimf->LocalVarSigTok == 0)
+    {
+        goto EndLocal;
+    }
+
+    hr = pMDImport->GetSigFromToken(pimf->LocalVarSigTok,
+                                    &sigLocal,
+                                    &cbSigLocal);
+
+    DoParse((sig_byte *) sigLocal, cbSigLocal);
+
+    EndLocal:
+
+    hr = S_OK;
+
+    Cleanup:
+    return hr;
+
+    Error:
+    goto Cleanup;
+}
+
+
+ // Simple helper to print an intro line for a class
+void PrintHeader(LPCWSTR wszClassName, mdTypeDef td, LPCSTR szCategory)
+{
+    printf("\n--------------------------------------------\n");
+    printf("%S (0x%x):\t%s\n", wszClassName, td, szCategory);
+    printf("--------------------------------------------\n\n");
+}
+
+
+ // Combines above functions to print the methods, properties, and fields of a class
+HRESULT PrintTypedef(ModuleID moduleID, IMetaDataImport* pMDImport, mdTypeDef td)
+{
+    HRESULT hr;
+    HCORENUM hEnum = NULL;
+    mdMethodDef aMethods[100];
+    mdFieldDef aFields[100];
+    mdFieldDef aProperties[100];
+    ULONG cMethodDefs;
+    ULONG cFields;
+    ULONG cProperties;
+    ULONG i;
+    WCHAR wszTdName[200];
+    ULONG cchTdName;
+    DWORD dwTypeDefFlags;
+    mdToken tkExtends;
+    BOOL fMore;
+
+    hr = pMDImport->GetTypeDefProps(td, // [IN] TypeDef token for inquiry.
+                                    wszTdName, // [OUT] Put name here.
+                                    dimensionof(wszTdName), // [IN] size of name buffer in wide chars.
+                                    &cchTdName, // [OUT] put size of name (wide chars) here.
+                                    &dwTypeDefFlags, // [OUT] Put flags here.
+                                    &tkExtends); // [OUT] Put base class TypeDef/TypeRef here.
+    if (FAILED(hr))
+    {
+        goto Error;
+    }
+
+    PrintHeader(wszTdName, td, "METHODDEFS");
+    fMore = TRUE;
+    while (fMore)
+    {
+        hr = pMDImport->EnumMethods(&hEnum,
+                                    td, // [IN] TypeDef to scope the enumeration. 
+                                    aMethods, // [OUT] Put MethodDefs here. 
+                                    dimensionof(aMethods), // [IN] Max MethodDefs to put. 
+                                    &cMethodDefs); // [OUT] Put # put here. 
+        if (FAILED(hr))
+        {
+            goto Error;
+        }
+
+        if (hr == S_FALSE)
+        {
+            fMore = FALSE;
+        }
+
+        for (i=0; i < cMethodDefs; i++)
+        {
+            hr = PrintMethodDef(moduleID, pMDImport, wszTdName, aMethods[i]);
+            if (FAILED(hr))
+            {
+                 // do you care? If so, do something about this.
+            }
+        }
+    }
+
+    pMDImport->CloseEnum(hEnum);
+    hEnum = NULL;
+
+    PrintHeader(wszTdName, td, "FIELDS");
+    fMore = TRUE;
+    while (fMore)
+    {
+        hr = pMDImport->EnumFields(&hEnum,
+                                   td, 
+                                   Fields, 
+                                   dimensionof(aFields),
+                                   &cFields);
+
+        if (FAILED(hr))
+        {
+            goto Error;
+        }
+
+        if (hr == S_FALSE)
+        {
+            fMore = FALSE;
+        }
+
+        for (i=0; i < cFields; i++)
+        {
+            hr = PrintField(moduleID, pMDImport, wszTdName, aFields[i]);
+            if (FAILED(hr))
+            {
+                               // do you care? If so, do something about this.
+            }
+        }
+    }
+
+    pMDImport->CloseEnum(hEnum);
+    hEnum = NULL;
+
+    PrintHeader(wszTdName, td, "PROPERTIES");
+    fMore = TRUE;
+    while (fMore)
+    {
+        hr = pMDImport->EnumProperties(&hEnum,
+                                                                          td, 
+                                                                          aProperties, 
+                                                                          dimensionof(aProperties),
+                                                                          &cProperties); 
+        if (FAILED(hr))
+        {
+            goto Error;
+        }
+
+        if (hr == S_FALSE)
+        {
+            fMore = FALSE;
+        }
+
+        for (i=0; i < cProperties; i++)
+        {
+            hr = PrintProperty(moduleID, pMDImport, wszTdName, aProperties[i]);
+            if (FAILED(hr))
+            {
+                               // do you care? If so, do something about this.
+            }
+        }
+    }
+
+    pMDImport->CloseEnum(hEnum);
+    hEnum = NULL;
+
+    hr = S_OK;
+
+    Cleanup:
+    if (hEnum != NULL)
+    {
+        pMDImport->CloseEnum(hEnum);
+    }
+    return hr;
+
+    Error:
+    goto Cleanup;
+}
+
+
+ // Enumerates the typedefs in a module via the metadata interface, and calls PrintTypedef
+ // on each one
+HRESULT PrintMetadata(ModuleID moduleID, IMetaDataImport* pMDImport)
+{
+    HRESULT hr;
+    HCORENUM hEnum = NULL;
+    mdTypeDef aTypeDefs[100];
+    ULONG cTypeDefs;
+    ULONG i;
+    BOOL fMoreTypeDefs = TRUE;
+
+    while (fMoreTypeDefs)
+    {
+        hr = pMDImport->EnumTypeDefs(&hEnum,
+                                                                aTypeDefs,
+                                                                dimensionof(aTypeDefs),
+                                                                &cTypeDefs);
+        if (FAILED(hr))
+        {
+            goto Error;
+        }
+
+        if (hr == S_FALSE)
+        {
+            fMoreTypeDefs = FALSE;
+        }
+
+        for (i=0; i < cTypeDefs; i++)
+        {
+            hr = PrintTypedef(moduleID, pMDImport, aTypeDefs[i]);
+            if (FAILED(hr))
+            {
+                               // do you care? If so, do something about this.
+            }
+        }
+    }
+
+    hr = S_OK;
+
+    Cleanup:
+    if (hEnum != NULL)
+    {
+        pMDImport->CloseEnum(hEnum);
+    }
+    return hr;
+
+    Error:
+    goto Cleanup;
+}
+
+
+ // ****************************************************************
+ // Add this to your profiler's ICorProfilerCallback2::ModuleLoadFinished implementation.
+ // It is assumed your copy of the ICorProfilerInfo2 interface may be accessed via
+ // g_pProfilerInfo. Change the code to fit your profiler as appropriate.
+ // ****************************************************************
+ //
+ // As a module gets loaded, this callback implementation initiates the pretty-printer to
+ // log all the types to stdout.
+HRESULT CYourProfImpl::ModuleLoadFinished( ModuleID moduleID, HRESULT hrStatus )
+{
+    HRESULT hr;
+    LPCBYTE pbBaseLoadAddr;
+    WCHAR wszName[300];
+    ULONG cchNameIn = dimensionof(wszName);
+    ULONG cchNameOut;
+    AssemblyID assemblyID;
+
+    hr = g_pProfilerInfo->GetModuleInfo(moduleID,
+                                                                           &pbBaseLoadAddr,
+                                                                           cchNameIn,
+                                                                           &cchNameOut,
+                                                                           wszName,
+                                                                           &assemblyID);
+    if (FAILED(hr))
+    {
+        return hr;
+    }
+
+    printf("MODULE LOAD FINISHED: %S\n", wszName);
+
+    IMetaDataImport *pMDImport = NULL;
+    hr = g_pProfilerInfo->GetModuleMetaData(moduleID,
+                                                                               ofRead,
+                                                                               IID_IMetaDataImport,
+                                                                               (IUnknown **)&pMDImport );
+    if (FAILED(hr))
+    {
+        return hr;
+    }
+
+    hr = PrintMetadata(moduleID, pMDImport);
+    if (FAILED(hr))
+    {
+               // Do any error handling as appropriate
+    }
+
+    hr = S_OK;
+
+    Cleanup:
+    return hr;
+
+    Error:
+    goto Cleanup;
+}
index 0a273a0..e62bb00 100644 (file)
@@ -1 +1,1051 @@
-// This blog post originally appeared on David Broman's blog on 10/13/2005\r\r// Sig ::= MethodDefSig | MethodRefSig | StandAloneMethodSig | FieldSig | PropertySig | LocalVarSig\r// MethodDefSig ::= [[HASTHIS] [EXPLICITTHIS]] (DEFAULT|VARARG|GENERIC GenParamCount) ParamCount RetType Param*\r// MethodRefSig ::= [[HASTHIS] [EXPLICITTHIS]] VARARG ParamCount RetType Param* [SENTINEL Param+]\r// StandAloneMethodSig ::= [[HASTHIS] [EXPLICITTHIS]] (DEFAULT|VARARG|C|STDCALL|THISCALL|FASTCALL) \r// ParamCount RetType Param* [SENTINEL Param+]\r// FieldSig ::= FIELD CustomMod* Type\r// PropertySig ::= PROPERTY [HASTHIS] ParamCount CustomMod* Type Param*\r// LocalVarSig ::= LOCAL_SIG Count (TYPEDBYREF | ([CustomMod] [Constraint])* [BYREF] Type)+ \r\r// -------------\r\r// CustomMod ::= ( CMOD_OPT | CMOD_REQD ) ( TypeDefEncoded | TypeRefEncoded )\r// Constraint ::= #define ELEMENT_TYPE_PINNED\r// Param ::= CustomMod* ( TYPEDBYREF | [BYREF] Type )\r// RetType ::= CustomMod* ( VOID | TYPEDBYREF | [BYREF] Type )\r// Type ::= ( BOOLEAN | CHAR | I1 | U1 | U2 | U2 | I4 | U4 | I8 | U8 | R4 | R8 | I | U |\r// | VALUETYPE TypeDefOrRefEncoded\r// | CLASS TypeDefOrRefEncoded\r// | STRING \r// | OBJECT\r// | PTR CustomMod* VOID\r// | PTR CustomMod* Type\r// | FNPTR MethodDefSig\r// | FNPTR MethodRefSig\r// | ARRAY Type ArrayShape\r// | SZARRAY CustomMod* Type\r// | GENERICINST (CLASS | VALUETYPE) TypeDefOrRefEncoded GenArgCount Type*\r// | VAR Number\r// | MVAR Number\r\r// ArrayShape ::= Rank NumSizes Size* NumLoBounds LoBound*\r\r// TypeDefOrRefEncoded ::= TypeDefEncoded | TypeRefEncoded\r// TypeDefEncoded ::= 32-bit-3-part-encoding-for-typedefs-and-typerefs\r// TypeRefEncoded ::= 32-bit-3-part-encoding-for-typedefs-and-typerefs\r\r// ParamCount ::= 29-bit-encoded-integer\r// GenArgCount ::= 29-bit-encoded-integer\r// Count ::= 29-bit-encoded-integer\r// Rank ::= 29-bit-encoded-integer\r// NumSizes ::= 29-bit-encoded-integer\r// Size ::= 29-bit-encoded-integer\r// NumLoBounds ::= 29-bit-encoded-integer\r// LoBounds ::= 29-bit-encoded-integer\r// Number ::= 29-bit-encoded-integer\r\r\r #define ELEMENT_TYPE_END 0x00 //Marks end of a list\r #define ELEMENT_TYPE_VOID 0x01\r #define ELEMENT_TYPE_BOOLEAN 0x02\r #define ELEMENT_TYPE_CHAR 0x03\r #define ELEMENT_TYPE_I1 0x04\r #define ELEMENT_TYPE_U1 0x05\r #define ELEMENT_TYPE_I2 0x06\r #define ELEMENT_TYPE_U2 0x07\r #define ELEMENT_TYPE_I4 0x08\r #define ELEMENT_TYPE_U4 0x09\r #define ELEMENT_TYPE_I8 0x0a\r #define ELEMENT_TYPE_U8 0x0b\r #define ELEMENT_TYPE_R4 0x0c\r #define ELEMENT_TYPE_R8 0x0d\r #define ELEMENT_TYPE_STRING 0x0e\r #define ELEMENT_TYPE_PTR 0x0f // Followed by type\r #define ELEMENT_TYPE_BYREF 0x10 // Followed by type\r #define ELEMENT_TYPE_VALUETYPE 0x11 // Followed by TypeDef or TypeRef token\r #define ELEMENT_TYPE_CLASS 0x12 // Followed by TypeDef or TypeRef token\r #define ELEMENT_TYPE_VAR 0x13 // Generic parameter in a generic type definition, represented as number\r #define ELEMENT_TYPE_ARRAY 0x14 // type rank boundsCount bound1 â€¦ loCount lo1 â€¦\r #define ELEMENT_TYPE_GENERICINST 0x15 // Generic type instantiation. Followed by type type-arg-count type-1 ... type-n\r #define ELEMENT_TYPE_TYPEDBYREF 0x16\r #define ELEMENT_TYPE_I 0x18 // System.IntPtr\r #define ELEMENT_TYPE_U 0x19 // System.UIntPtr\r #define ELEMENT_TYPE_FNPTR 0x1b // Followed by full method signature\r #define ELEMENT_TYPE_OBJECT 0x1c // System.Object\r #define ELEMENT_TYPE_SZARRAY 0x1d // Single-dim array with 0 lower bound\r\r #define ELEMENT_TYPE_MVAR 0x1e // Generic parameter in a generic method definition,represented as number\r #define ELEMENT_TYPE_CMOD_REQD 0x1f // Required modifier : followed by a TypeDef or TypeRef token\r #define ELEMENT_TYPE_CMOD_OPT 0x20 // Optional modifier : followed by a TypeDef or TypeRef token\r #define ELEMENT_TYPE_INTERNAL 0x21 // Implemented within the CLI\r #define ELEMENT_TYPE_MODIFIER 0x40 // Or’d with following element types\r #define ELEMENT_TYPE_SENTINEL 0x41 // Sentinel for vararg method signature\r #define ELEMENT_TYPE_PINNED 0x45 // Denotes a local variable that points at a pinned object\r\r #define SIG_METHOD_DEFAULT 0x0 // default calling convention\r #define SIG_METHOD_C 0x1 // C calling convention\r #define SIG_METHOD_STDCALL 0x2 // Stdcall calling convention\r #define SIG_METHOD_THISCALL 0x3 // thiscall calling convention\r #define SIG_METHOD_FASTCALL 0x4 // fastcall calling convention\r #define SIG_METHOD_VARARG 0x5 // vararg calling convention\r #define SIG_FIELD 0x6 // encodes a field\r #define SIG_LOCAL_SIG 0x7 // used for the .locals directive\r #define SIG_PROPERTY 0x8 // used to encode a property\r\r\r #define SIG_GENERIC 0x10 // used to indicate that the method has one or more generic parameters.\r #define SIG_HASTHIS 0x20 // used to encode the keyword instance in the calling convention\r #define SIG_EXPLICITTHIS 0x40 // used to encode the keyword explicit in the calling convention\r\r #define SIG_INDEX_TYPE_TYPEDEF 0 // ParseTypeDefOrRefEncoded returns this as the out index type for typedefs\r #define SIG_INDEX_TYPE_TYPEREF 1 // ParseTypeDefOrRefEncoded returns this as the out index type for typerefs\r #define SIG_INDEX_TYPE_TYPESPEC 2 // ParseTypeDefOrRefEncoded returns this as the out index type for typespecs\r\r\rtypedef unsigned char sig_byte;\rtypedef unsigned char sig_elem_type;\rtypedef unsigned char sig_index_type;\rtypedef unsigned int sig_index;\rtypedef unsigned int sig_count;\rtypedef unsigned int sig_mem_number;\r\rclass SigParser\r{\rprivate:\r      sig_byte *pbBase;\r      sig_byte *pbCur;\r       sig_byte *pbEnd;\r\rpublic: \r     bool Parse(sig_byte *blob, sig_count len);\r\rprivate:\r   bool ParseByte(sig_byte *pbOut);\r       bool ParseNumber(sig_count *pOut);\r     bool ParseTypeDefOrRefEncoded(sig_index_type *pOutIndexType, sig_index *pOutIndex);\r\r   bool ParseMethod(sig_elem_type);\r       bool ParseField(sig_elem_type);\r        bool ParseProperty(sig_elem_type);\r     bool ParseLocals(sig_elem_type);\r       bool ParseLocal();\r     bool ParseOptionalCustomMods();\r        bool ParseOptionalCustomModsOrConstraint();\r    bool ParseCustomMod();\r bool ParseRetType();\r   bool ParseType();\r      bool ParseParam();\r     bool ParseArrayShape();\r\rprotected:\r\r   // subtype these methods to create your parser side-effects\r\r   //----------------------------------------------------\r\r        // a method with given elem_type\r       virtual void NotifyBeginMethod(sig_elem_type elem_type) {}\r     virtual void NotifyEndMethod() {}\r\r     // total parameters for the method\r     virtual void NotifyParamCount(sig_count) {}\r\r   // starting a return type\r      virtual void NotifyBeginRetType() {}\r   virtual void NotifyEndRetType() {}\r\r    // starting a parameter\r        virtual void NotifyBeginParam() {}\r     virtual void NotifyEndParam() {}\r\r      // sentinel indication the location of the "..." in the method signature\r       virtual void NotifySentinal() {}\r\r      // number of generic parameters in this method signature (if any)\r      virtual void NotifyGenericParamCount(sig_count) {}\r\r    //----------------------------------------------------\r\r        // a field with given elem_type\r        virtual void NotifyBeginField(sig_elem_type elem_type) {}\r      virtual void NotifyEndField() {}\r\r      //----------------------------------------------------\r\r        // a block of locals with given elem_type (always just LOCAL_SIG for now)\r      virtual void NotifyBeginLocals(sig_elem_type elem_type) {}\r     virtual void NotifyEndLocals() {}\r\r     // count of locals with a block\r        virtual void NotifyLocalsCount(sig_count) {}\r\r  // starting a new local within a local block\r   virtual void NotifyBeginLocal() {}\r     virtual void NotifyEndLocal() {}\r\r      // the only constraint available to locals at the moment is ELEMENT_TYPE_PINNED\r        virtual void NotifyConstraint(sig_elem_type elem_type) {}\r\r\r    //----------------------------------------------------\r\r        // a property with given element type\r  virtual void NotifyBeginProperty(sig_elem_type elem_type) {}\r   virtual void NotifyEndProperty() {}\r\r   //----------------------------------------------------\r\r        // starting array shape information for array types\r    virtual void NotifyBeginArrayShape() {}\r        virtual void NotifyEndArrayShape() {}\r\r         // array rank (total number of dimensions)\r     virtual void NotifyRank(sig_count) {}\r\r         // number of dimensions with specified sizes followed by the size of each\r      virtual void NotifyNumSizes(sig_count) {}\r      virtual void NotifySize(sig_count) {}\r\r         // BUG BUG lower bounds can be negative, how can this be encoded?\r      // number of dimensions with specified lower bounds followed by lower bound of each \r   virtual void NotifyNumLoBounds(sig_count) {} \r  virtual void NotifyLoBound(sig_count) {}\r\r      //----------------------------------------------------\r\r\r       // starting a normal type (occurs in many contexts such as param, field, local, etc)\r   virtual void NotifyBeginType() {};\r     virtual void NotifyEndType() {};\r\r      virtual void NotifyTypedByref() {}\r\r    // the type has the 'byref' modifier on it -- this normally proceeds the type definition in the context\r        // the type is used, so for instance a parameter might have the byref modifier on it\r   // so this happens before the BeginType in that context\r        virtual void NotifyByref() {}\r\r         // the type is "VOID" (this has limited uses, function returns and void pointer)\r       virtual void NotifyVoid() {}\r\r    // the type has the indicated custom modifiers (which can be optional or required)\r   virtual void NotifyCustomMod(sig_elem_type cmod, sig_index_type indexType, sig_index index) {}\r\r    // the type is a simple type, the elem_type defines it fully\r       virtual void NotifyTypeSimple(sig_elem_type elem_type) {}\r\r     // the type is specified by the given index of the given index type (normally a type index in the type metadata)\r       // this callback is normally qualified by other ones such as NotifyTypeClass or NotifyTypeValueType\r    virtual void NotifyTypeDefOrRef(sig_index_type indexType, int index) {}\r\r       // the type is an instance of a generic\r        // elem_type indicates value_type or class\r     // indexType and index indicate the metadata for the type in question\r  // number indicates the number of type specifications for the generic types that will follow\r   virtual void NotifyTypeGenericInst(sig_elem_type elem_type, sig_index_type indexType, sig_index index, sig_mem_number number) {}\r\r      // the type is the type of the nth generic type parameter for the class\r        virtual void NotifyTypeGenericTypeVariable(sig_mem_number number) {} \r\r         // the type is the type of the nth generic type parameter for the member\r       virtual void NotifyTypeGenericMemberVariable(sig_mem_number number) {} \r\r       // the type will be a value type\r       virtual void NotifyTypeValueType() {}\r\r         // the type will be a class\r    virtual void NotifyTypeClass() {}\r\r     // the type is a pointer to a type (nested type notifications follow)\r  virtual void NotifyTypePointer() {}\r\r   // the type is a function pointer, followed by the type of the function\r        virtual void NotifyTypeFunctionPointer() {}\r\r   // the type is an array, this is followed by the array shape, see above, as well as modifiers and element type\r virtual void NotifyTypeArray() {}\r\r     // the type is a simple zero-based array, this has no shape but does have custom modifiers and element type\r    virtual void NotifyTypeSzArray() {}\r};\r\r //----------------------------------------------------\r\r\rbool SigParser::Parse(sig_byte *pb, sig_count cbBuffer)\r{\r    pbBase = pb;\r   pbCur = pb;\r    pbEnd = pbBase + cbBuffer;\r\r    sig_elem_type elem_type;\r\r      if (!ParseByte(&elem_type))\r            return false;\r\r switch (elem_type & 0xf)\r       {\r              case SIG_METHOD_DEFAULT: // default calling convention\r         case SIG_METHOD_C: // C calling convention\r             case SIG_METHOD_STDCALL: // Stdcall calling convention\r         case SIG_METHOD_THISCALL: // thiscall calling convention\r               case SIG_METHOD_FASTCALL: // fastcall calling convention\r               case SIG_METHOD_VARARG: // vararg calling convention\r                   return ParseMethod(elem_type);\r                 break;\r \r               case SIG_FIELD: // encodes a field\r                     return ParseField(elem_type);\r                  break;\r \r               case SIG_LOCAL_SIG: // used for the .locals directive\r                  return ParseLocals(elem_type);\r                         break;\r \r               case SIG_PROPERTY: // used to encode a property\r                        return ParseProperty(elem_type);\r                       break;\r \r               default:\r                       // unknown signature\r                   break;\r }\r\r     return false;\r}\r\r\rbool SigParser::ParseByte(sig_byte *pbOut)\r{\r if (pbCur < pbEnd)\r     {\r              *pbOut = *pbCur;\r               pbCur++;\r               return true;\r   }\r\r     return false;\r}\r\r\rbool SigParser::ParseMethod(sig_elem_type elem_type)\r{\r       // MethodDefSig ::= [[HASTHIS] [EXPLICITTHIS]] (DEFAULT|VARARG|GENERIC GenParamCount)\r  // ParamCount RetType Param* [SENTINEL Param+]\r\r        NotifyBeginMethod(elem_type);\r\r sig_count gen_param_count;\r     sig_count param_count;\r\r        if (elem_type & SIG_GENERIC)\r   {\r              if (!ParseNumber(&gen_param_count))\r            {\r                      return false;\r          }\r\r             NotifyGenericParamCount(gen_param_count); \r     }\r\r     if (!ParseNumber(¶m_count))\r   {\r              return false;\r  }\r\r     NotifyParamCount(param_count);\r\r        if (!ParseRetType())\r   {\r              return false;\r  }\r\r     bool fEncounteredSentinal = false;\r\r    for (sig_count i = 0; i < param_count; i++)\r    {\r              if (pbCur >= pbEnd)\r            {\r                      return false;\r          }\r\r             if (*pbCur == ELEMENT_TYPE_SENTINEL)\r           {\r                      if (fEncounteredSentinal)\r                      {\r                              return false;\r                  }\r\r                     fEncounteredSentinal = true;\r                   NotifySentinal();\r                      pbCur++;\r               }\r\r             if (!ParseParam())\r             {\r                      return false;\r          }\r      }\r\r     NotifyEndMethod();\r\r    return true;\r}\r\r\rbool SigParser::ParseField(sig_elem_type elem_type)\r{\r         // FieldSig ::= FIELD CustomMod* Type\r\r NotifyBeginField(elem_type);\r\r  if (!ParseOptionalCustomMods())\r        {\r              return false;\r  }\r\r     if (!ParseType())\r      {\r              return false;\r  }\r\r     NotifyEndField();\r\r     return true;\r}\r\r\rbool SigParser::ParseProperty(sig_elem_type elem_type)\r{\r      // PropertySig ::= PROPERTY [HASTHIS] ParamCount CustomMod* Type Param*\r\r       NotifyBeginProperty(elem_type);\r\r       sig_count param_count;\r\r        if (!ParseNumber(&param_count))\r        {\r              return false;\r  }\r\r     NotifyParamCount(param_count);\r\r        if (!ParseOptionalCustomMods())\r        {\r              return false;\r  }\r\r     if (!ParseType())\r      {\r              return false;\r  }\r\r     for (sig_count i = 0; i < param_count; i++)\r    {\r              if (!ParseParam())\r             {\r                      return false;\r          }\r      }\r\r     NotifyEndProperty();\r\r  return true;\r}\r\r\rbool SigParser::ParseLocals(sig_elem_type elem_type)\r{\r        // LocalVarSig ::= LOCAL_SIG Count (TYPEDBYREF | ([CustomMod] [Constraint])* [BYREF] Type)+ \r\r  NotifyBeginLocals(elem_type);\r\r sig_count local_count;\r\r        if (!ParseNumber(&local_count))\r        {\r              return false;\r  }\r\r     NotifyLocalsCount(local_count);\r\r       for (sig_count i = 0; i < local_count; i++)\r    {\r              if (!ParseLocal())\r             {\r                      return false;\r          }\r      }\r\r     NotifyEndLocals();\r\r    return true;\r}\r\r\rbool SigParser::ParseLocal()\r{\r        //TYPEDBYREF | ([CustomMod] [Constraint])* [BYREF] Type\r        NotifyBeginLocal();\r\r   if (pbCur >= pbEnd)\r    {\r              return false;\r  }\r\r     if (*pbCur == ELEMENT_TYPE_TYPEDBYREF)\r {\r              NotifyTypedByref();\r            pbCur++;\r               goto Success;\r  }\r\r     if (!ParseOptionalCustomModsOrConstraint())\r    {\r              return false;\r  }\r\r     if (pbCur >= pbEnd)\r    {\r              return false;\r  }\r\r     if (*pbCur == ELEMENT_TYPE_BYREF)\r      {\r              NotifyByref();\r         pbCur++;\r       }\r\r     if (!ParseType())\r      {\r              return false;\r  }\r\r     Success:\r       NotifyEndLocal();\r      return true;\r}\r\r\rbool SigParser::ParseOptionalCustomModsOrConstraint()\r\r      for (;;)\r       {\r              if (pbCur >= pbEnd)\r            {\r                      return true;\r           }\r\r             switch (*pbCur)\r                {\r                      case ELEMENT_TYPE_CMOD_OPT:\r                    case ELEMENT_TYPE_CMOD_REQD:\r                           if (!ParseCustomMod())\r                         {\r                                      return false;\r                          }\r                      break;\r\r                        case ELEMENT_TYPE_PINNED:\r                              NotifyConstraint(*pbCur);\r                              pbCur++;\r                               break;\r\r                        default:\r                               return true;\r           }\r      }\r\r     return false;\r}\r\r\rbool SigParser::ParseOptionalCustomMods()\r{\r  for (;;)\r       {\r              if (pbCur >= pbEnd)\r            {\r                      return true;\r           }\r\r             switch (*pbCur)\r                {\r                      case ELEMENT_TYPE_CMOD_OPT:\r                    case ELEMENT_TYPE_CMOD_REQD:\r                           if (!ParseCustomMod())\r                         {\r                                      return false;\r                          }\r                              break; \r\r                       default:\r                               return true;\r           }\r      }\r\r     return false;\r}\r\r\r\rbool SigParser::ParseCustomMod()\r{\r  sig_elem_type cmod = 0;\r        sig_index index;\r       sig_index_type indexType;\r\r     if (!ParseByte(&cmod))\r {\r              return false;\r  }\r\r     if (cmod == ELEMENT_TYPE_CMOD_OPT || cmod == ELEMENT_TYPE_CMOD_REQD)\r   {\r              if (!ParseTypeDefOrRefEncoded(&indexType, &index))\r             {\r                      return false;\r          }\r\r             NotifyCustomMod(cmod, indexType, index);\r               return true;\r   }\r\r     return false;\r}\r\r\rbool SigParser::ParseParam()\r{\r       // Param ::= CustomMod* ( TYPEDBYREF | [BYREF] Type )\r\r NotifyBeginParam();\r\r   if (!ParseOptionalCustomMods())\r        {\r              return false;\r  }\r\r     if (pbCur >= pbEnd)\r    {\r              return false;\r  }\r\r     if (*pbCur == ELEMENT_TYPE_TYPEDBYREF)\r {\r              NotifyTypedByref();\r            pbCur++;\r               goto Success;\r  }\r\r     if (*pbCur == ELEMENT_TYPE_BYREF)\r      {\r              NotifyByref();\r         pbCur++;\r       }\r\r     if (!ParseType())\r      {\r              return false;\r  }\r\r     Success:\r       NotifyEndParam();\r      return true;\r}\r\r\rbool SigParser::ParseRetType()\r{\r      // RetType ::= CustomMod* ( VOID | TYPEDBYREF | [BYREF] Type )\r\r        NotifyBeginRetType();\r\r if (!ParseOptionalCustomMods())\r        {\r              return false;\r  }\r\r     if (pbCur >= pbEnd)\r    {\r              return false;\r  }\r\r     if (*pbCur == ELEMENT_TYPE_TYPEDBYREF)\r {\r              NotifyTypedByref();\r            pbCur++;\r               goto Success;\r  }\r\r     if (*pbCur == ELEMENT_TYPE_VOID)\r       {\r              NotifyVoid();\r          pbCur++;\r               goto Success;\r  }\r\r     if (*pbCur == ELEMENT_TYPE_BYREF)\r      {\r              NotifyByref();\r         pbCur++;\r       }\r\r     if (!ParseType())\r      {\r              return false;\r  }\r\r     Success: \r      NotifyEndRetType();\r    return true;\r}\r\rbool SigParser::ParseArrayShape()\r{\r    sig_count rank;\r        sig_count numsizes;\r    sig_count size;\r\r       // ArrayShape ::= Rank NumSizes Size* NumLoBounds LoBound*\r     NotifyBeginArrayShape();\r       if (!ParseNumber(&rank))\r       {\r              return false;\r  }\r\r     NotifyRank(rank);\r\r     if (!ParseNumber(&numsizes))\r   {\r              return false;\r  }\r\r     NotifyNumSizes(numsizes);\r\r     for (sig_count i = 0; i < numsizes; i++)\r       {\r              if (!ParseNumber(&size))\r               {\r                      return false;\r          }\r\r             NotifySize(size);\r      }\r\r     if (!ParseNumber(&numsizes))\r   {\r              return false;\r  }\r\r     NotifyNumLoBounds(numsizes);\r\r  for (sig_count i = 0; i < numsizes; i++)\r       {\r              if (!ParseNumber(&size))\r               {\r                      return false;\r          }\r\r             NotifyLoBound(size);\r   }\r\r     NotifyEndArrayShape();\r return true; \r}\r\rbool SigParser::ParseType()\r{\r // Type ::= ( BOOLEAN | CHAR | I1 | U1 | U2 | U2 | I4 | U4 | I8 | U8 | R4 | R8 | I | U |\r       //       | VALUETYPE TypeDefOrRefEncoded\r       //       | CLASS TypeDefOrRefEncoded\r   //       | STRING \r     //       | OBJECT\r      //       | PTR CustomMod* VOID\r //       | PTR CustomMod* Type\r //       | FNPTR MethodDefSig\r  //       | FNPTR MethodRefSig\r  //       | ARRAY Type ArrayShape\r       //       | SZARRAY CustomMod* Type\r     //       | GENERICINST (CLASS | VALUETYPE) TypeDefOrRefEncoded GenArgCount Type *\r      //       | VAR Number\r  //       | MVAR Number\r\r        NotifyBeginType();\r\r    sig_elem_type elem_type;\r       sig_index index;\r       sig_mem_number number;\r sig_index_type indexType;\r\r     if (!ParseByte(&elem_type))\r            return false;\r\r switch (elem_type)\r     {\r              case ELEMENT_TYPE_BOOLEAN:\r             case ELEMENT_TYPE_CHAR:\r                case ELEMENT_TYPE_I1:\r          case ELEMENT_TYPE_U1: \r         case ELEMENT_TYPE_U2: \r         case ELEMENT_TYPE_I2: \r         case ELEMENT_TYPE_I4: \r         case ELEMENT_TYPE_U4: \r         case ELEMENT_TYPE_I8: \r         case ELEMENT_TYPE_U8: \r         case ELEMENT_TYPE_R4: \r         case ELEMENT_TYPE_R8: \r         case ELEMENT_TYPE_I:\r           case ELEMENT_TYPE_U:\r           case ELEMENT_TYPE_STRING:\r              case ELEMENT_TYPE_OBJECT:\r              // simple types\r                        NotifyTypeSimple(elem_type);\r                   break;\r\r                case ELEMENT_TYPE_PTR:\r                 // PTR CustomMod* VOID\r                 // PTR CustomMod* Type\r\r                        NotifyTypePointer();\r\r                  if (!ParseOptionalCustomMods())\r                        {\r                              return false;\r                  }\r\r                     if (pbCur >= pbEnd)\r                    {\r                              return false;\r                  }\r\r                     if (*pbCur == ELEMENT_TYPE_VOID)\r                       {\r                              pbCur++;\r                               NotifyVoid();\r                          break;\r                 }\r\r                     if (!ParseType())\r                      {\r                              return false;\r                  }\r\r                     break;\r\r                case ELEMENT_TYPE_CLASS: \r                      // CLASS TypeDefOrRefEncoded\r                   NotifyTypeClass();\r\r                    if (!ParseTypeDefOrRefEncoded(&indexType, &index))\r                     {\r                              return false;\r                  }\r\r                     NotifyTypeDefOrRef(indexType, index); \r                 break;\r\r                case ELEMENT_TYPE_VALUETYPE: \r                  //VALUETYPE TypeDefOrRefEncoded\r                        NotifyTypeValueType();\r\r                        if (!ParseTypeDefOrRefEncoded(&indexType, &index))\r                     {\r                              return false;\r                  }\r\r                     NotifyTypeDefOrRef(indexType, index); \r                 break;\r\r                case ELEMENT_TYPE_FNPTR:\r                       // FNPTR MethodDefSig\r                  // FNPTR MethodRefSig\r                  NotifyTypeFunctionPointer();\r\r                  if (!ParseByte(&elem_type))\r                    {\r                              return false;\r                  }\r\r                     if (!ParseMethod(elem_type))\r                   {\r                              return false;\r                  }\r\r                     break;\r\r                case ELEMENT_TYPE_ARRAY:\r                       // ARRAY Type ArrayShape\r                       NotifyTypeArray();\r\r                    if (!ParseType())\r                      {\r                              return false;\r                  }\r\r                     if (!ParseArrayShape())\r                        {\r                              return false;\r                  }\r                      break;\r\r                case ELEMENT_TYPE_SZARRAY:\r                     // SZARRAY CustomMod* Type\r\r                    NotifyTypeSzArray();\r\r                  if (!ParseOptionalCustomMods())\r                        {\r                              return false;\r                  }\r\r                     if (!ParseType())\r                      {\r                              return false;\r                  }\r\r                     break;\r\r                case ELEMENT_TYPE_GENERICINST:\r                 // GENERICINST (CLASS | VALUETYPE) TypeDefOrRefEncoded GenArgCount Type *\r\r                     if (!ParseByte(&elem_type))\r                    {\r                              return false;\r                  }\r\r                     if (elem_type != ELEMENT_TYPE_CLASS && elem_type != ELEMENT_TYPE_VALUETYPE)\r                    {\r                              return false;\r                  }\r\r                     if (!ParseTypeDefOrRefEncoded(&indexType, &index))\r                     {\r                              return false;\r                  }\r\r                     if (!ParseNumber(&number))\r                     {\r                              return false;\r                  }\r\r                     NotifyTypeGenericInst(elem_type, indexType, index, number);\r\r                   {\r                              for (sig_mem_number i=0; i < number; i++)\r                              {\r                                      if (!ParseType())\r                                      {\r                                              return false;\r                                  }\r                              }\r                      }\r\r                     break;\r\r                case ELEMENT_TYPE_VAR:\r                 // VAR Number\r                  if (!ParseNumber(&number))\r                     {\r                              return false;\r                  }\r\r                     NotifyTypeGenericTypeVariable(number);\r                 break;\r\r                case ELEMENT_TYPE_MVAR:\r                        // MVAR Number\r                 if (!ParseNumber(&number))\r                     {\r                              return false;\r                  }\r\r                     NotifyTypeGenericMemberVariable(number);\r                       break;\r }\r\r     NotifyEndType();\r\r      return true;\r}\r\rbool SigParser::ParseTypeDefOrRefEncoded(sig_index_type *pIndexTypeOut, sig_index *pIndexOut)\r{\r        // parse an encoded typedef or typeref\r\r        sig_count encoded = 0;\r\r        if (!ParseNumber(&encoded))\r    {\r              return false;\r  }\r\r     *pIndexTypeOut = (sig_index_type) (encoded & 0x3);\r     *pIndexOut = (encoded >> 2);\r   return true;\r}\r\rbool SigParser::ParseNumber(sig_count *pOut)\r{\r // parse the variable length number format (0-4 bytes)\r\r        sig_byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;\r\r      // at least one byte in the encoding, read that\r\r       if (!ParseByte(&b1))\r   {\r              return false;\r  }\r\r     if (b1 == 0xff)\r        {\r               // special encoding of 'NULL'\r          // not sure what this means as a number, don't expect to see it except for string lengths\r              // which we don't encounter anyway so calling it an error\r             return false;\r  }\r\r     // early out on 1 byte encoding\r        if ( (b1 & 0x80) == 0)\r {\r              *pOut = (int)b1;\r               return true;\r   }\r\r     // now at least 2 bytes in the encoding, read 2nd byte\r if (!ParseByte(&b2))\r   {\r              return false;\r  }\r\r     // early out on 2 byte encoding\r        if ( (b1 & 0x40) == 0)\r {\r              *pOut = (((b1 & 0x3f) << 8) | b2);\r             return true;\r   }\r\r     // must be a 4 byte encoding\r\r  if ( (b1 & 0x20) != 0) \r        {\r              // 4 byte encoding has this bit clear -- error if not\r          return false;\r  } \r\r    if (!ParseByte(&b3))\r   {\r              return false;\r  }\r\r     if (!ParseByte(&b4))\r   {\r              return false;\r  }\r\r     *pOut = ((b1 & 0x1f) << 24) | (b2 << 16) | (b3 << 8) | b4;\r     return true;\r}\r
\ No newline at end of file
+// This blog post originally appeared on David Broman's blog on 10/13/2005
+
+// Sig ::= MethodDefSig | MethodRefSig | StandAloneMethodSig | FieldSig | PropertySig | LocalVarSig
+// MethodDefSig ::= [[HASTHIS] [EXPLICITTHIS]] (DEFAULT|VARARG|GENERIC GenParamCount) ParamCount RetType Param*
+// MethodRefSig ::= [[HASTHIS] [EXPLICITTHIS]] VARARG ParamCount RetType Param* [SENTINEL Param+]
+// StandAloneMethodSig ::= [[HASTHIS] [EXPLICITTHIS]] (DEFAULT|VARARG|C|STDCALL|THISCALL|FASTCALL) 
+// ParamCount RetType Param* [SENTINEL Param+]
+// FieldSig ::= FIELD CustomMod* Type
+// PropertySig ::= PROPERTY [HASTHIS] ParamCount CustomMod* Type Param*
+// LocalVarSig ::= LOCAL_SIG Count (TYPEDBYREF | ([CustomMod] [Constraint])* [BYREF] Type)+ 
+
+// -------------
+
+// CustomMod ::= ( CMOD_OPT | CMOD_REQD ) ( TypeDefEncoded | TypeRefEncoded )
+// Constraint ::= #define ELEMENT_TYPE_PINNED
+// Param ::= CustomMod* ( TYPEDBYREF | [BYREF] Type )
+// RetType ::= CustomMod* ( VOID | TYPEDBYREF | [BYREF] Type )
+// Type ::= ( BOOLEAN | CHAR | I1 | U1 | U2 | U2 | I4 | U4 | I8 | U8 | R4 | R8 | I | U |
+// | VALUETYPE TypeDefOrRefEncoded
+// | CLASS TypeDefOrRefEncoded
+// | STRING 
+// | OBJECT
+// | PTR CustomMod* VOID
+// | PTR CustomMod* Type
+// | FNPTR MethodDefSig
+// | FNPTR MethodRefSig
+// | ARRAY Type ArrayShape
+// | SZARRAY CustomMod* Type
+// | GENERICINST (CLASS | VALUETYPE) TypeDefOrRefEncoded GenArgCount Type*
+// | VAR Number
+// | MVAR Number
+
+// ArrayShape ::= Rank NumSizes Size* NumLoBounds LoBound*
+
+// TypeDefOrRefEncoded ::= TypeDefEncoded | TypeRefEncoded
+// TypeDefEncoded ::= 32-bit-3-part-encoding-for-typedefs-and-typerefs
+// TypeRefEncoded ::= 32-bit-3-part-encoding-for-typedefs-and-typerefs
+
+// ParamCount ::= 29-bit-encoded-integer
+// GenArgCount ::= 29-bit-encoded-integer
+// Count ::= 29-bit-encoded-integer
+// Rank ::= 29-bit-encoded-integer
+// NumSizes ::= 29-bit-encoded-integer
+// Size ::= 29-bit-encoded-integer
+// NumLoBounds ::= 29-bit-encoded-integer
+// LoBounds ::= 29-bit-encoded-integer
+// Number ::= 29-bit-encoded-integer
+
+
+ #define ELEMENT_TYPE_END 0x00 //Marks end of a list
+ #define ELEMENT_TYPE_VOID 0x01
+ #define ELEMENT_TYPE_BOOLEAN 0x02
+ #define ELEMENT_TYPE_CHAR 0x03
+ #define ELEMENT_TYPE_I1 0x04
+ #define ELEMENT_TYPE_U1 0x05
+ #define ELEMENT_TYPE_I2 0x06
+ #define ELEMENT_TYPE_U2 0x07
+ #define ELEMENT_TYPE_I4 0x08
+ #define ELEMENT_TYPE_U4 0x09
+ #define ELEMENT_TYPE_I8 0x0a
+ #define ELEMENT_TYPE_U8 0x0b
+ #define ELEMENT_TYPE_R4 0x0c
+ #define ELEMENT_TYPE_R8 0x0d
+ #define ELEMENT_TYPE_STRING 0x0e
+ #define ELEMENT_TYPE_PTR 0x0f // Followed by type
+ #define ELEMENT_TYPE_BYREF 0x10 // Followed by type
+ #define ELEMENT_TYPE_VALUETYPE 0x11 // Followed by TypeDef or TypeRef token
+ #define ELEMENT_TYPE_CLASS 0x12 // Followed by TypeDef or TypeRef token
+ #define ELEMENT_TYPE_VAR 0x13 // Generic parameter in a generic type definition, represented as number
+ #define ELEMENT_TYPE_ARRAY 0x14 // type rank boundsCount bound1 â€¦ loCount lo1 â€¦
+ #define ELEMENT_TYPE_GENERICINST 0x15 // Generic type instantiation. Followed by type type-arg-count type-1 ... type-n
+ #define ELEMENT_TYPE_TYPEDBYREF 0x16
+ #define ELEMENT_TYPE_I 0x18 // System.IntPtr
+ #define ELEMENT_TYPE_U 0x19 // System.UIntPtr
+ #define ELEMENT_TYPE_FNPTR 0x1b // Followed by full method signature
+ #define ELEMENT_TYPE_OBJECT 0x1c // System.Object
+ #define ELEMENT_TYPE_SZARRAY 0x1d // Single-dim array with 0 lower bound
+
+ #define ELEMENT_TYPE_MVAR 0x1e // Generic parameter in a generic method definition,represented as number
+ #define ELEMENT_TYPE_CMOD_REQD 0x1f // Required modifier : followed by a TypeDef or TypeRef token
+ #define ELEMENT_TYPE_CMOD_OPT 0x20 // Optional modifier : followed by a TypeDef or TypeRef token
+ #define ELEMENT_TYPE_INTERNAL 0x21 // Implemented within the CLI
+ #define ELEMENT_TYPE_MODIFIER 0x40 // Or’d with following element types
+ #define ELEMENT_TYPE_SENTINEL 0x41 // Sentinel for vararg method signature
+ #define ELEMENT_TYPE_PINNED 0x45 // Denotes a local variable that points at a pinned object
+
+ #define SIG_METHOD_DEFAULT 0x0 // default calling convention
+ #define SIG_METHOD_C 0x1 // C calling convention
+ #define SIG_METHOD_STDCALL 0x2 // Stdcall calling convention
+ #define SIG_METHOD_THISCALL 0x3 // thiscall calling convention
+ #define SIG_METHOD_FASTCALL 0x4 // fastcall calling convention
+ #define SIG_METHOD_VARARG 0x5 // vararg calling convention
+ #define SIG_FIELD 0x6 // encodes a field
+ #define SIG_LOCAL_SIG 0x7 // used for the .locals directive
+ #define SIG_PROPERTY 0x8 // used to encode a property
+
+
+ #define SIG_GENERIC 0x10 // used to indicate that the method has one or more generic parameters.
+ #define SIG_HASTHIS 0x20 // used to encode the keyword instance in the calling convention
+ #define SIG_EXPLICITTHIS 0x40 // used to encode the keyword explicit in the calling convention
+
+ #define SIG_INDEX_TYPE_TYPEDEF 0 // ParseTypeDefOrRefEncoded returns this as the out index type for typedefs
+ #define SIG_INDEX_TYPE_TYPEREF 1 // ParseTypeDefOrRefEncoded returns this as the out index type for typerefs
+ #define SIG_INDEX_TYPE_TYPESPEC 2 // ParseTypeDefOrRefEncoded returns this as the out index type for typespecs
+
+
+typedef unsigned char sig_byte;
+typedef unsigned char sig_elem_type;
+typedef unsigned char sig_index_type;
+typedef unsigned int sig_index;
+typedef unsigned int sig_count;
+typedef unsigned int sig_mem_number;
+
+class SigParser
+{
+private:
+       sig_byte *pbBase;
+       sig_byte *pbCur;
+       sig_byte *pbEnd;
+
+public: 
+       bool Parse(sig_byte *blob, sig_count len);
+
+private:
+       bool ParseByte(sig_byte *pbOut);
+       bool ParseNumber(sig_count *pOut);
+       bool ParseTypeDefOrRefEncoded(sig_index_type *pOutIndexType, sig_index *pOutIndex);
+
+       bool ParseMethod(sig_elem_type);
+       bool ParseField(sig_elem_type);
+       bool ParseProperty(sig_elem_type);
+       bool ParseLocals(sig_elem_type);
+       bool ParseLocal();
+       bool ParseOptionalCustomMods();
+       bool ParseOptionalCustomModsOrConstraint();
+       bool ParseCustomMod();
+       bool ParseRetType();
+       bool ParseType();
+       bool ParseParam();
+       bool ParseArrayShape();
+
+protected:
+
+       // subtype these methods to create your parser side-effects
+
+       //----------------------------------------------------
+
+       // a method with given elem_type
+       virtual void NotifyBeginMethod(sig_elem_type elem_type) {}
+       virtual void NotifyEndMethod() {}
+
+       // total parameters for the method
+       virtual void NotifyParamCount(sig_count) {}
+
+       // starting a return type
+       virtual void NotifyBeginRetType() {}
+       virtual void NotifyEndRetType() {}
+
+       // starting a parameter
+       virtual void NotifyBeginParam() {}
+       virtual void NotifyEndParam() {}
+
+       // sentinel indication the location of the "..." in the method signature
+       virtual void NotifySentinal() {}
+
+       // number of generic parameters in this method signature (if any)
+       virtual void NotifyGenericParamCount(sig_count) {}
+
+       //----------------------------------------------------
+
+       // a field with given elem_type
+       virtual void NotifyBeginField(sig_elem_type elem_type) {}
+       virtual void NotifyEndField() {}
+
+       //----------------------------------------------------
+
+       // a block of locals with given elem_type (always just LOCAL_SIG for now)
+       virtual void NotifyBeginLocals(sig_elem_type elem_type) {}
+       virtual void NotifyEndLocals() {}
+
+       // count of locals with a block
+       virtual void NotifyLocalsCount(sig_count) {}
+
+       // starting a new local within a local block
+       virtual void NotifyBeginLocal() {}
+       virtual void NotifyEndLocal() {}
+
+       // the only constraint available to locals at the moment is ELEMENT_TYPE_PINNED
+       virtual void NotifyConstraint(sig_elem_type elem_type) {}
+
+
+       //----------------------------------------------------
+
+       // a property with given element type
+       virtual void NotifyBeginProperty(sig_elem_type elem_type) {}
+       virtual void NotifyEndProperty() {}
+
+       //----------------------------------------------------
+
+       // starting array shape information for array types
+       virtual void NotifyBeginArrayShape() {}
+       virtual void NotifyEndArrayShape() {}
+
+       // array rank (total number of dimensions)
+       virtual void NotifyRank(sig_count) {}
+
+       // number of dimensions with specified sizes followed by the size of each
+       virtual void NotifyNumSizes(sig_count) {}
+       virtual void NotifySize(sig_count) {}
+
+       // BUG BUG lower bounds can be negative, how can this be encoded?
+       // number of dimensions with specified lower bounds followed by lower bound of each 
+       virtual void NotifyNumLoBounds(sig_count) {} 
+       virtual void NotifyLoBound(sig_count) {}
+
+       //----------------------------------------------------
+
+
+       // starting a normal type (occurs in many contexts such as param, field, local, etc)
+       virtual void NotifyBeginType() {};
+       virtual void NotifyEndType() {};
+
+       virtual void NotifyTypedByref() {}
+
+       // the type has the 'byref' modifier on it -- this normally proceeds the type definition in the context
+       // the type is used, so for instance a parameter might have the byref modifier on it
+       // so this happens before the BeginType in that context
+       virtual void NotifyByref() {}
+
+       // the type is "VOID" (this has limited uses, function returns and void pointer)
+       virtual void NotifyVoid() {}
+
+    // the type has the indicated custom modifiers (which can be optional or required)
+       virtual void NotifyCustomMod(sig_elem_type cmod, sig_index_type indexType, sig_index index) {}
+
+    // the type is a simple type, the elem_type defines it fully
+       virtual void NotifyTypeSimple(sig_elem_type elem_type) {}
+
+       // the type is specified by the given index of the given index type (normally a type index in the type metadata)
+       // this callback is normally qualified by other ones such as NotifyTypeClass or NotifyTypeValueType
+       virtual void NotifyTypeDefOrRef(sig_index_type indexType, int index) {}
+
+       // the type is an instance of a generic
+       // elem_type indicates value_type or class
+       // indexType and index indicate the metadata for the type in question
+       // number indicates the number of type specifications for the generic types that will follow
+       virtual void NotifyTypeGenericInst(sig_elem_type elem_type, sig_index_type indexType, sig_index index, sig_mem_number number) {}
+
+       // the type is the type of the nth generic type parameter for the class
+       virtual void NotifyTypeGenericTypeVariable(sig_mem_number number) {} 
+
+       // the type is the type of the nth generic type parameter for the member
+       virtual void NotifyTypeGenericMemberVariable(sig_mem_number number) {} 
+
+       // the type will be a value type
+       virtual void NotifyTypeValueType() {}
+
+       // the type will be a class
+       virtual void NotifyTypeClass() {}
+
+       // the type is a pointer to a type (nested type notifications follow)
+       virtual void NotifyTypePointer() {}
+
+       // the type is a function pointer, followed by the type of the function
+       virtual void NotifyTypeFunctionPointer() {}
+
+       // the type is an array, this is followed by the array shape, see above, as well as modifiers and element type
+       virtual void NotifyTypeArray() {}
+
+       // the type is a simple zero-based array, this has no shape but does have custom modifiers and element type
+       virtual void NotifyTypeSzArray() {}
+};
+
+ //----------------------------------------------------
+
+
+bool SigParser::Parse(sig_byte *pb, sig_count cbBuffer)
+{
+       pbBase = pb;
+       pbCur = pb;
+       pbEnd = pbBase + cbBuffer;
+
+       sig_elem_type elem_type;
+
+       if (!ParseByte(&elem_type))
+               return false;
+
+       switch (elem_type & 0xf)
+       {
+               case SIG_METHOD_DEFAULT: // default calling convention
+               case SIG_METHOD_C: // C calling convention
+               case SIG_METHOD_STDCALL: // Stdcall calling convention
+               case SIG_METHOD_THISCALL: // thiscall calling convention
+               case SIG_METHOD_FASTCALL: // fastcall calling convention
+               case SIG_METHOD_VARARG: // vararg calling convention
+                       return ParseMethod(elem_type);
+                       break;
+               case SIG_FIELD: // encodes a field
+                       return ParseField(elem_type);
+                       break;
+               case SIG_LOCAL_SIG: // used for the .locals directive
+                       return ParseLocals(elem_type);
+                       break;
+               case SIG_PROPERTY: // used to encode a property
+                       return ParseProperty(elem_type);
+                       break;
+               default:
+                       // unknown signature
+                       break;
+       }
+
+       return false;
+}
+
+
+bool SigParser::ParseByte(sig_byte *pbOut)
+{
+       if (pbCur < pbEnd)
+       {
+               *pbOut = *pbCur;
+               pbCur++;
+               return true;
+       }
+
+       return false;
+}
+
+
+bool SigParser::ParseMethod(sig_elem_type elem_type)
+{
+       // MethodDefSig ::= [[HASTHIS] [EXPLICITTHIS]] (DEFAULT|VARARG|GENERIC GenParamCount)
+       // ParamCount RetType Param* [SENTINEL Param+]
+
+       NotifyBeginMethod(elem_type);
+
+       sig_count gen_param_count;
+       sig_count param_count;
+
+       if (elem_type & SIG_GENERIC)
+       {
+               if (!ParseNumber(&gen_param_count))
+               {
+                       return false;
+               }
+
+               NotifyGenericParamCount(gen_param_count); 
+       }
+
+       if (!ParseNumber(¶m_count))
+       {
+               return false;
+       }
+
+       NotifyParamCount(param_count);
+
+       if (!ParseRetType())
+       {
+               return false;
+       }
+
+       bool fEncounteredSentinal = false;
+
+       for (sig_count i = 0; i < param_count; i++)
+       {
+               if (pbCur >= pbEnd)
+               {
+                       return false;
+               }
+
+               if (*pbCur == ELEMENT_TYPE_SENTINEL)
+               {
+                       if (fEncounteredSentinal)
+                       {
+                               return false;
+                       }
+
+                       fEncounteredSentinal = true;
+                       NotifySentinal();
+                       pbCur++;
+               }
+
+               if (!ParseParam())
+               {
+                       return false;
+               }
+       }
+
+       NotifyEndMethod();
+
+       return true;
+}
+
+
+bool SigParser::ParseField(sig_elem_type elem_type)
+{
+       // FieldSig ::= FIELD CustomMod* Type
+
+       NotifyBeginField(elem_type);
+
+       if (!ParseOptionalCustomMods())
+       {
+               return false;
+       }
+
+       if (!ParseType())
+       {
+               return false;
+       }
+
+       NotifyEndField();
+
+       return true;
+}
+
+
+bool SigParser::ParseProperty(sig_elem_type elem_type)
+{
+       // PropertySig ::= PROPERTY [HASTHIS] ParamCount CustomMod* Type Param*
+
+       NotifyBeginProperty(elem_type);
+
+       sig_count param_count;
+
+       if (!ParseNumber(&param_count))
+       {
+               return false;
+       }
+
+       NotifyParamCount(param_count);
+
+       if (!ParseOptionalCustomMods())
+       {
+               return false;
+       }
+
+       if (!ParseType())
+       {
+               return false;
+       }
+
+       for (sig_count i = 0; i < param_count; i++)
+       {
+               if (!ParseParam())
+               {
+                       return false;
+               }
+       }
+
+       NotifyEndProperty();
+
+       return true;
+}
+
+
+bool SigParser::ParseLocals(sig_elem_type elem_type)
+{
+       // LocalVarSig ::= LOCAL_SIG Count (TYPEDBYREF | ([CustomMod] [Constraint])* [BYREF] Type)+ 
+
+       NotifyBeginLocals(elem_type);
+
+       sig_count local_count;
+
+       if (!ParseNumber(&local_count))
+       {
+               return false;
+       }
+
+       NotifyLocalsCount(local_count);
+
+       for (sig_count i = 0; i < local_count; i++)
+       {
+               if (!ParseLocal())
+               {
+                       return false;
+               }
+       }
+
+       NotifyEndLocals();
+
+       return true;
+}
+
+
+bool SigParser::ParseLocal()
+{
+       //TYPEDBYREF | ([CustomMod] [Constraint])* [BYREF] Type
+       NotifyBeginLocal();
+
+       if (pbCur >= pbEnd)
+       {
+               return false;
+       }
+
+       if (*pbCur == ELEMENT_TYPE_TYPEDBYREF)
+       {
+               NotifyTypedByref();
+               pbCur++;
+               goto Success;
+       }
+
+       if (!ParseOptionalCustomModsOrConstraint())
+       {
+               return false;
+       }
+
+       if (pbCur >= pbEnd)
+       {
+               return false;
+       }
+
+       if (*pbCur == ELEMENT_TYPE_BYREF)
+       {
+               NotifyByref();
+               pbCur++;
+       }
+
+       if (!ParseType())
+       {
+               return false;
+       }
+
+       Success:
+       NotifyEndLocal();
+       return true;
+}
+
+
+bool SigParser::ParseOptionalCustomModsOrConstraint()
+{ 
+       for (;;)
+       {
+               if (pbCur >= pbEnd)
+               {
+                       return true;
+               }
+
+               switch (*pbCur)
+               {
+                       case ELEMENT_TYPE_CMOD_OPT:
+                       case ELEMENT_TYPE_CMOD_REQD:
+                               if (!ParseCustomMod())
+                               {
+                                       return false;
+                               }
+                       break;
+
+                       case ELEMENT_TYPE_PINNED:
+                               NotifyConstraint(*pbCur);
+                               pbCur++;
+                               break;
+
+                       default:
+                               return true;
+               }
+       }
+
+       return false;
+}
+
+
+bool SigParser::ParseOptionalCustomMods()
+{
+       for (;;)
+       {
+               if (pbCur >= pbEnd)
+               {
+                       return true;
+               }
+
+               switch (*pbCur)
+               {
+                       case ELEMENT_TYPE_CMOD_OPT:
+                       case ELEMENT_TYPE_CMOD_REQD:
+                               if (!ParseCustomMod())
+                               {
+                                       return false;
+                               }
+                               break; 
+
+                       default:
+                               return true;
+               }
+       }
+
+       return false;
+}
+
+
+
+bool SigParser::ParseCustomMod()
+{
+       sig_elem_type cmod = 0;
+       sig_index index;
+       sig_index_type indexType;
+
+       if (!ParseByte(&cmod))
+       {
+               return false;
+       }
+
+       if (cmod == ELEMENT_TYPE_CMOD_OPT || cmod == ELEMENT_TYPE_CMOD_REQD)
+       {
+               if (!ParseTypeDefOrRefEncoded(&indexType, &index))
+               {
+                       return false;
+               }
+
+               NotifyCustomMod(cmod, indexType, index);
+               return true;
+       }
+
+       return false;
+}
+
+
+bool SigParser::ParseParam()
+{
+       // Param ::= CustomMod* ( TYPEDBYREF | [BYREF] Type )
+
+       NotifyBeginParam();
+
+       if (!ParseOptionalCustomMods())
+       {
+               return false;
+       }
+
+       if (pbCur >= pbEnd)
+       {
+               return false;
+       }
+
+       if (*pbCur == ELEMENT_TYPE_TYPEDBYREF)
+       {
+               NotifyTypedByref();
+               pbCur++;
+               goto Success;
+       }
+
+       if (*pbCur == ELEMENT_TYPE_BYREF)
+       {
+               NotifyByref();
+               pbCur++;
+       }
+
+       if (!ParseType())
+       {
+               return false;
+       }
+
+       Success:
+       NotifyEndParam();
+       return true;
+}
+
+
+bool SigParser::ParseRetType()
+{
+       // RetType ::= CustomMod* ( VOID | TYPEDBYREF | [BYREF] Type )
+
+       NotifyBeginRetType();
+
+       if (!ParseOptionalCustomMods())
+       {
+               return false;
+       }
+
+       if (pbCur >= pbEnd)
+       {
+               return false;
+       }
+
+       if (*pbCur == ELEMENT_TYPE_TYPEDBYREF)
+       {
+               NotifyTypedByref();
+               pbCur++;
+               goto Success;
+       }
+
+       if (*pbCur == ELEMENT_TYPE_VOID)
+       {
+               NotifyVoid();
+               pbCur++;
+               goto Success;
+       }
+
+       if (*pbCur == ELEMENT_TYPE_BYREF)
+       {
+               NotifyByref();
+               pbCur++;
+       }
+
+       if (!ParseType())
+       {
+               return false;
+       }
+
+       Success: 
+       NotifyEndRetType();
+       return true;
+}
+
+bool SigParser::ParseArrayShape()
+{
+       sig_count rank;
+       sig_count numsizes;
+       sig_count size;
+
+       // ArrayShape ::= Rank NumSizes Size* NumLoBounds LoBound*
+       NotifyBeginArrayShape();
+       if (!ParseNumber(&rank))
+       {
+               return false;
+       }
+
+       NotifyRank(rank);
+
+       if (!ParseNumber(&numsizes))
+       {
+               return false;
+       }
+
+       NotifyNumSizes(numsizes);
+
+       for (sig_count i = 0; i < numsizes; i++)
+       {
+               if (!ParseNumber(&size))
+               {
+                       return false;
+               }
+
+               NotifySize(size);
+       }
+
+       if (!ParseNumber(&numsizes))
+       {
+               return false;
+       }
+
+       NotifyNumLoBounds(numsizes);
+
+       for (sig_count i = 0; i < numsizes; i++)
+       {
+               if (!ParseNumber(&size))
+               {
+                       return false;
+               }
+
+               NotifyLoBound(size);
+       }
+
+       NotifyEndArrayShape();
+       return true; 
+}
+
+bool SigParser::ParseType()
+{
+       // Type ::= ( BOOLEAN | CHAR | I1 | U1 | U2 | U2 | I4 | U4 | I8 | U8 | R4 | R8 | I | U |
+       //       | VALUETYPE TypeDefOrRefEncoded
+       //       | CLASS TypeDefOrRefEncoded
+       //       | STRING 
+       //       | OBJECT
+       //       | PTR CustomMod* VOID
+       //       | PTR CustomMod* Type
+       //       | FNPTR MethodDefSig
+       //       | FNPTR MethodRefSig
+       //       | ARRAY Type ArrayShape
+       //       | SZARRAY CustomMod* Type
+       //       | GENERICINST (CLASS | VALUETYPE) TypeDefOrRefEncoded GenArgCount Type *
+       //       | VAR Number
+       //       | MVAR Number
+
+       NotifyBeginType();
+
+       sig_elem_type elem_type;
+       sig_index index;
+       sig_mem_number number;
+       sig_index_type indexType;
+
+       if (!ParseByte(&elem_type))
+               return false;
+
+       switch (elem_type)
+       {
+               case ELEMENT_TYPE_BOOLEAN:
+               case ELEMENT_TYPE_CHAR:
+               case ELEMENT_TYPE_I1:
+               case ELEMENT_TYPE_U1: 
+               case ELEMENT_TYPE_U2: 
+               case ELEMENT_TYPE_I2: 
+               case ELEMENT_TYPE_I4: 
+               case ELEMENT_TYPE_U4: 
+               case ELEMENT_TYPE_I8: 
+               case ELEMENT_TYPE_U8: 
+               case ELEMENT_TYPE_R4: 
+               case ELEMENT_TYPE_R8: 
+               case ELEMENT_TYPE_I:
+               case ELEMENT_TYPE_U:
+               case ELEMENT_TYPE_STRING:
+               case ELEMENT_TYPE_OBJECT:
+               // simple types
+                       NotifyTypeSimple(elem_type);
+                       break;
+
+               case ELEMENT_TYPE_PTR:
+                       // PTR CustomMod* VOID
+                       // PTR CustomMod* Type
+
+                       NotifyTypePointer();
+
+                       if (!ParseOptionalCustomMods())
+                       {
+                               return false;
+                       }
+
+                       if (pbCur >= pbEnd)
+                       {
+                               return false;
+                       }
+
+                       if (*pbCur == ELEMENT_TYPE_VOID)
+                       {
+                               pbCur++;
+                               NotifyVoid();
+                               break;
+                       }
+
+                       if (!ParseType())
+                       {
+                               return false;
+                       }
+
+                       break;
+
+               case ELEMENT_TYPE_CLASS: 
+                       // CLASS TypeDefOrRefEncoded
+                       NotifyTypeClass();
+
+                       if (!ParseTypeDefOrRefEncoded(&indexType, &index))
+                       {
+                               return false;
+                       }
+
+                       NotifyTypeDefOrRef(indexType, index); 
+                       break;
+
+               case ELEMENT_TYPE_VALUETYPE: 
+                       //VALUETYPE TypeDefOrRefEncoded
+                       NotifyTypeValueType();
+
+                       if (!ParseTypeDefOrRefEncoded(&indexType, &index))
+                       {
+                               return false;
+                       }
+
+                       NotifyTypeDefOrRef(indexType, index); 
+                       break;
+
+               case ELEMENT_TYPE_FNPTR:
+                       // FNPTR MethodDefSig
+                       // FNPTR MethodRefSig
+                       NotifyTypeFunctionPointer();
+
+                       if (!ParseByte(&elem_type))
+                       {
+                               return false;
+                       }
+
+                       if (!ParseMethod(elem_type))
+                       {
+                               return false;
+                       }
+
+                       break;
+
+               case ELEMENT_TYPE_ARRAY:
+                       // ARRAY Type ArrayShape
+                       NotifyTypeArray();
+
+                       if (!ParseType())
+                       {
+                               return false;
+                       }
+
+                       if (!ParseArrayShape())
+                       {
+                               return false;
+                       }
+                       break;
+
+               case ELEMENT_TYPE_SZARRAY:
+                       // SZARRAY CustomMod* Type
+
+                       NotifyTypeSzArray();
+
+                       if (!ParseOptionalCustomMods())
+                       {
+                               return false;
+                       }
+
+                       if (!ParseType())
+                       {
+                               return false;
+                       }
+
+                       break;
+
+               case ELEMENT_TYPE_GENERICINST:
+                       // GENERICINST (CLASS | VALUETYPE) TypeDefOrRefEncoded GenArgCount Type *
+
+                       if (!ParseByte(&elem_type))
+                       {
+                               return false;
+                       }
+
+                       if (elem_type != ELEMENT_TYPE_CLASS && elem_type != ELEMENT_TYPE_VALUETYPE)
+                       {
+                               return false;
+                       }
+
+                       if (!ParseTypeDefOrRefEncoded(&indexType, &index))
+                       {
+                               return false;
+                       }
+
+                       if (!ParseNumber(&number))
+                       {
+                               return false;
+                       }
+
+                       NotifyTypeGenericInst(elem_type, indexType, index, number);
+
+                       {
+                               for (sig_mem_number i=0; i < number; i++)
+                               {
+                                       if (!ParseType())
+                                       {
+                                               return false;
+                                       }
+                               }
+                       }
+
+                       break;
+
+               case ELEMENT_TYPE_VAR:
+                       // VAR Number
+                       if (!ParseNumber(&number))
+                       {
+                               return false;
+                       }
+
+                       NotifyTypeGenericTypeVariable(number);
+                       break;
+
+               case ELEMENT_TYPE_MVAR:
+                       // MVAR Number
+                       if (!ParseNumber(&number))
+                       {
+                               return false;
+                       }
+
+                       NotifyTypeGenericMemberVariable(number);
+                       break;
+       }
+
+       NotifyEndType();
+
+       return true;
+}
+
+bool SigParser::ParseTypeDefOrRefEncoded(sig_index_type *pIndexTypeOut, sig_index *pIndexOut)
+{
+       // parse an encoded typedef or typeref
+
+       sig_count encoded = 0;
+
+       if (!ParseNumber(&encoded))
+       {
+               return false;
+       }
+
+       *pIndexTypeOut = (sig_index_type) (encoded & 0x3);
+       *pIndexOut = (encoded >> 2);
+       return true;
+}
+
+bool SigParser::ParseNumber(sig_count *pOut)
+{
+       // parse the variable length number format (0-4 bytes)
+
+       sig_byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;
+
+       // at least one byte in the encoding, read that
+
+       if (!ParseByte(&b1))
+       {
+               return false;
+       }
+
+       if (b1 == 0xff)
+       {
+                // special encoding of 'NULL'
+                // not sure what this means as a number, don't expect to see it except for string lengths
+                // which we don't encounter anyway so calling it an error
+               return false;
+       }
+
+       // early out on 1 byte encoding
+       if ( (b1 & 0x80) == 0)
+       {
+               *pOut = (int)b1;
+               return true;
+       }
+
+       // now at least 2 bytes in the encoding, read 2nd byte
+       if (!ParseByte(&b2))
+       {
+               return false;
+       }
+
+       // early out on 2 byte encoding
+       if ( (b1 & 0x40) == 0)
+       {
+               *pOut = (((b1 & 0x3f) << 8) | b2);
+               return true;
+       }
+
+       // must be a 4 byte encoding
+
+       if ( (b1 & 0x20) != 0) 
+       {
+               // 4 byte encoding has this bit clear -- error if not
+               return false;
+       } 
+
+       if (!ParseByte(&b3))
+       {
+               return false;
+       }
+
+       if (!ParseByte(&b4))
+       {
+               return false;
+       }
+
+       *pOut = ((b1 & 0x1f) << 24) | (b2 << 16) | (b3 << 8) | b4;
+       return true;
+}