first commit
This commit is contained in:
BIN
internal/winmd/metadata/Windows.AI.winmd
Normal file
BIN
internal/winmd/metadata/Windows.AI.winmd
Normal file
Binary file not shown.
BIN
internal/winmd/metadata/Windows.ApplicationModel.winmd
Normal file
BIN
internal/winmd/metadata/Windows.ApplicationModel.winmd
Normal file
Binary file not shown.
BIN
internal/winmd/metadata/Windows.Data.winmd
Normal file
BIN
internal/winmd/metadata/Windows.Data.winmd
Normal file
Binary file not shown.
BIN
internal/winmd/metadata/Windows.Devices.winmd
Normal file
BIN
internal/winmd/metadata/Windows.Devices.winmd
Normal file
Binary file not shown.
BIN
internal/winmd/metadata/Windows.Foundation.winmd
Normal file
BIN
internal/winmd/metadata/Windows.Foundation.winmd
Normal file
Binary file not shown.
BIN
internal/winmd/metadata/Windows.Gaming.winmd
Normal file
BIN
internal/winmd/metadata/Windows.Gaming.winmd
Normal file
Binary file not shown.
BIN
internal/winmd/metadata/Windows.Globalization.winmd
Normal file
BIN
internal/winmd/metadata/Windows.Globalization.winmd
Normal file
Binary file not shown.
BIN
internal/winmd/metadata/Windows.Graphics.winmd
Normal file
BIN
internal/winmd/metadata/Windows.Graphics.winmd
Normal file
Binary file not shown.
BIN
internal/winmd/metadata/Windows.Management.Setup.winmd
Normal file
BIN
internal/winmd/metadata/Windows.Management.Setup.winmd
Normal file
Binary file not shown.
BIN
internal/winmd/metadata/Windows.Management.winmd
Normal file
BIN
internal/winmd/metadata/Windows.Management.winmd
Normal file
Binary file not shown.
BIN
internal/winmd/metadata/Windows.Media.winmd
Normal file
BIN
internal/winmd/metadata/Windows.Media.winmd
Normal file
Binary file not shown.
BIN
internal/winmd/metadata/Windows.Networking.winmd
Normal file
BIN
internal/winmd/metadata/Windows.Networking.winmd
Normal file
Binary file not shown.
BIN
internal/winmd/metadata/Windows.Perception.winmd
Normal file
BIN
internal/winmd/metadata/Windows.Perception.winmd
Normal file
Binary file not shown.
BIN
internal/winmd/metadata/Windows.Security.winmd
Normal file
BIN
internal/winmd/metadata/Windows.Security.winmd
Normal file
Binary file not shown.
BIN
internal/winmd/metadata/Windows.Services.winmd
Normal file
BIN
internal/winmd/metadata/Windows.Services.winmd
Normal file
Binary file not shown.
BIN
internal/winmd/metadata/Windows.Storage.winmd
Normal file
BIN
internal/winmd/metadata/Windows.Storage.winmd
Normal file
Binary file not shown.
BIN
internal/winmd/metadata/Windows.System.winmd
Normal file
BIN
internal/winmd/metadata/Windows.System.winmd
Normal file
Binary file not shown.
BIN
internal/winmd/metadata/Windows.UI.Xaml.winmd
Normal file
BIN
internal/winmd/metadata/Windows.UI.Xaml.winmd
Normal file
Binary file not shown.
BIN
internal/winmd/metadata/Windows.UI.winmd
Normal file
BIN
internal/winmd/metadata/Windows.UI.winmd
Normal file
Binary file not shown.
BIN
internal/winmd/metadata/Windows.Web.winmd
Normal file
BIN
internal/winmd/metadata/Windows.Web.winmd
Normal file
Binary file not shown.
76
internal/winmd/methoddef.go
Normal file
76
internal/winmd/methoddef.go
Normal file
@ -0,0 +1,76 @@
|
||||
package winmd
|
||||
|
||||
import (
|
||||
"github.com/tdakkota/win32metadata/md"
|
||||
"github.com/tdakkota/win32metadata/types"
|
||||
)
|
||||
|
||||
// GetMethodOverloadName finds and returns the overload attribute for the given method
|
||||
func GetMethodOverloadName(ctx *types.Context, methodDef *types.MethodDef) string {
|
||||
cAttrTable := ctx.Table(md.CustomAttribute)
|
||||
for i := uint32(0); i < cAttrTable.RowCount(); i++ {
|
||||
var cAttr types.CustomAttribute
|
||||
if err := cAttr.FromRow(cAttrTable.Row(i)); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// - Parent: The owner of the Attribute must be the given func
|
||||
if cAttrParentTable, _ := cAttr.Parent.Table(); cAttrParentTable != md.MethodDef {
|
||||
continue
|
||||
}
|
||||
|
||||
var parentMethodDef types.MethodDef
|
||||
row, ok := cAttr.Parent.Row(ctx)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if err := parentMethodDef.FromRow(row); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// does the blob belong to the method we're looking for?
|
||||
if parentMethodDef.Name != methodDef.Name || string(parentMethodDef.Signature) != string(methodDef.Signature) {
|
||||
continue
|
||||
}
|
||||
|
||||
// - Type: the attribute type must be the given type
|
||||
// the cAttr.Type table can be either a MemberRef or a MethodRef.
|
||||
// Since we are looking for a type, we will only consider the MemberRef.
|
||||
if cAttrTypeTable, _ := cAttr.Type.Table(); cAttrTypeTable != md.MemberRef {
|
||||
continue
|
||||
}
|
||||
|
||||
var attrTypeMemberRef types.MemberRef
|
||||
row, ok = cAttr.Type.Row(ctx)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if err := attrTypeMemberRef.FromRow(row); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// we need to check the MemberRef Class
|
||||
// the value can belong to several tables, but we are only going to check for TypeRef
|
||||
if classTable, _ := attrTypeMemberRef.Class.Table(); classTable != md.TypeRef {
|
||||
continue
|
||||
}
|
||||
|
||||
var attrTypeRef types.TypeRef
|
||||
row, ok = attrTypeMemberRef.Class.Row(ctx)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if err := attrTypeRef.FromRow(row); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if attrTypeRef.TypeNamespace+"."+attrTypeRef.TypeName == AttributeTypeOverloadAttribute {
|
||||
// Metadata values start with 0x01 0x00 and ends with 0x00 0x00
|
||||
mdVal := cAttr.Value[2 : len(cAttr.Value)-2]
|
||||
// the next value is the length of the string
|
||||
mdVal = mdVal[1:]
|
||||
return string(mdVal)
|
||||
}
|
||||
}
|
||||
return methodDef.Name
|
||||
}
|
89
internal/winmd/store.go
Normal file
89
internal/winmd/store.go
Normal file
@ -0,0 +1,89 @@
|
||||
package winmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/tdakkota/win32metadata/md"
|
||||
"github.com/tdakkota/win32metadata/types"
|
||||
)
|
||||
|
||||
// ClassNotFoundError is returned when a class is not found.
|
||||
type ClassNotFoundError struct {
|
||||
Class string
|
||||
}
|
||||
|
||||
func (e *ClassNotFoundError) Error() string {
|
||||
return fmt.Sprintf("class %s was not found", e.Class)
|
||||
}
|
||||
|
||||
// Store holds the windows metadata contexts. It can be used to get the metadata across multiple files.
|
||||
type Store struct {
|
||||
contexts map[string]*types.Context
|
||||
logger log.Logger
|
||||
}
|
||||
|
||||
// NewStore loads all windows metadata files and returns a new Store.
|
||||
func NewStore(logger log.Logger) (*Store, error) {
|
||||
contexts := make(map[string]*types.Context)
|
||||
|
||||
winmdFiles, err := allFiles()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// parse and store all files in memory
|
||||
for _, f := range winmdFiles {
|
||||
winmdCtx, err := parseWinMDFile(f.Name())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
contexts[f.Name()] = winmdCtx
|
||||
}
|
||||
|
||||
return &Store{
|
||||
contexts: contexts,
|
||||
logger: logger,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func parseWinMDFile(path string) (*types.Context, error) {
|
||||
f, err := open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() { _ = f.Close() }()
|
||||
|
||||
return types.FromPE(f)
|
||||
}
|
||||
|
||||
// TypeDefByName returns a type definition that matches the given name.
|
||||
func (mds *Store) TypeDefByName(class string) (*TypeDef, error) {
|
||||
// the type can belong to any of the contexts
|
||||
for _, ctx := range mds.contexts {
|
||||
if td := mds.typeDefByNameAndCtx(class, ctx); td != nil {
|
||||
return td, nil // return the first match
|
||||
}
|
||||
}
|
||||
return nil, &ClassNotFoundError{Class: class}
|
||||
}
|
||||
|
||||
func (mds *Store) typeDefByNameAndCtx(class string, ctx *types.Context) *TypeDef {
|
||||
typeDefTable := ctx.Table(md.TypeDef)
|
||||
for i := uint32(0); i < typeDefTable.RowCount(); i++ {
|
||||
var typeDef types.TypeDef
|
||||
if err := typeDef.FromRow(typeDefTable.Row(i)); err != nil {
|
||||
continue // keep searching instead of failing
|
||||
}
|
||||
|
||||
if typeDef.TypeNamespace+"."+typeDef.TypeName == class {
|
||||
return &TypeDef{
|
||||
TypeDef: typeDef,
|
||||
HasContext: HasContext{ctx},
|
||||
logger: mds.logger,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
310
internal/winmd/typedef.go
Normal file
310
internal/winmd/typedef.go
Normal file
@ -0,0 +1,310 @@
|
||||
package winmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
"github.com/tdakkota/win32metadata/md"
|
||||
"github.com/tdakkota/win32metadata/types"
|
||||
)
|
||||
|
||||
// TypeDef is a helper struct that wraps types.TypeDef and stores the original context
|
||||
// of the typeDef.
|
||||
type TypeDef struct {
|
||||
types.TypeDef
|
||||
HasContext
|
||||
|
||||
logger log.Logger
|
||||
}
|
||||
|
||||
// QualifiedID holds the namespace and the name of a qualified element. This may be a type, a static function or a field
|
||||
type QualifiedID struct {
|
||||
Namespace string
|
||||
Name string
|
||||
}
|
||||
|
||||
// GetValueForEnumField returns the value of the requested enum field.
|
||||
func (typeDef *TypeDef) GetValueForEnumField(fieldIndex uint32) (string, error) {
|
||||
// For each Enum value definition, there is a corresponding row in the Constant table to store the integer value for the enum value.
|
||||
tableConstants := typeDef.Ctx().Table(md.Constant)
|
||||
for i := uint32(0); i < tableConstants.RowCount(); i++ {
|
||||
var constant types.Constant
|
||||
if err := constant.FromRow(tableConstants.Row(i)); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if t, _ := constant.Parent.Table(); t != md.Field {
|
||||
continue
|
||||
}
|
||||
|
||||
// does the blob belong to the field we're looking for?
|
||||
// The parent is an index into the field table that holds the associated enum value record
|
||||
if constant.Parent.TableIndex() != fieldIndex {
|
||||
continue
|
||||
}
|
||||
|
||||
// The value is a blob that we need to read as little endian
|
||||
var blobIndex uint32
|
||||
for i, b := range constant.Value {
|
||||
blobIndex += uint32(b) << (i * 8)
|
||||
}
|
||||
return strconv.Itoa(int(blobIndex)), nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("no value found for field %d", fieldIndex)
|
||||
}
|
||||
|
||||
// GetAttributeWithType returns the value of the given attribute type and fails if not found.
|
||||
func (typeDef *TypeDef) GetAttributeWithType(lookupAttrTypeClass string) ([]byte, error) {
|
||||
result := typeDef.GetTypeDefAttributesWithType(lookupAttrTypeClass)
|
||||
if len(result) == 0 {
|
||||
return nil, fmt.Errorf("type %s has no custom attribute %s", typeDef.TypeNamespace+"."+typeDef.TypeName, lookupAttrTypeClass)
|
||||
} else if len(result) > 1 {
|
||||
_ = level.Warn(typeDef.logger).Log(
|
||||
"msg", "type has multiple custom attributes, returning the first one",
|
||||
"type", typeDef.TypeNamespace+"."+typeDef.TypeName,
|
||||
"attr", lookupAttrTypeClass,
|
||||
)
|
||||
}
|
||||
|
||||
return result[0], nil
|
||||
}
|
||||
|
||||
// GetTypeDefAttributesWithType returns the values of all the attributes that match the given type.
|
||||
func (typeDef *TypeDef) GetTypeDefAttributesWithType(lookupAttrTypeClass string) [][]byte {
|
||||
result := make([][]byte, 0)
|
||||
cAttrTable := typeDef.Ctx().Table(md.CustomAttribute)
|
||||
for i := uint32(0); i < cAttrTable.RowCount(); i++ {
|
||||
var cAttr types.CustomAttribute
|
||||
if err := cAttr.FromRow(cAttrTable.Row(i)); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// - Parent: The owner of the Attribute must be the given typeDef
|
||||
if cAttrParentTable, _ := cAttr.Parent.Table(); cAttrParentTable != md.TypeDef {
|
||||
continue
|
||||
}
|
||||
|
||||
var parentTypeDef TypeDef
|
||||
row, ok := cAttr.Parent.Row(typeDef.Ctx())
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if err := parentTypeDef.FromRow(row); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// does the blob belong to the type we're looking for?
|
||||
if parentTypeDef.TypeNamespace != typeDef.TypeNamespace || parentTypeDef.TypeName != typeDef.TypeName {
|
||||
continue
|
||||
}
|
||||
|
||||
// - Type: the attribute type must be the given type
|
||||
// the cAttr.Type table can be either a MemberRef or a MethodRef.
|
||||
// Since we are looking for a type, we will only consider the MemberRef.
|
||||
if cAttrTypeTable, _ := cAttr.Type.Table(); cAttrTypeTable != md.MemberRef {
|
||||
continue
|
||||
}
|
||||
|
||||
var attrTypeMemberRef types.MemberRef
|
||||
row, ok = cAttr.Type.Row(typeDef.Ctx())
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if err := attrTypeMemberRef.FromRow(row); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// we need to check the MemberRef Class
|
||||
// the value can belong to several tables, but we are only going to check for TypeRef
|
||||
if classTable, _ := attrTypeMemberRef.Class.Table(); classTable != md.TypeRef {
|
||||
continue
|
||||
}
|
||||
|
||||
var attrTypeRef types.TypeRef
|
||||
row, ok = attrTypeMemberRef.Class.Row(typeDef.Ctx())
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if err := attrTypeRef.FromRow(row); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if attrTypeRef.TypeNamespace+"."+attrTypeRef.TypeName == lookupAttrTypeClass {
|
||||
result = append(result, cAttr.Value)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// GetImplementedInterfaces returns the interfaces implemented by the type.
|
||||
func (typeDef *TypeDef) GetImplementedInterfaces() ([]QualifiedID, error) {
|
||||
interfaces := make([]QualifiedID, 0)
|
||||
|
||||
tableInterfaceImpl := typeDef.Ctx().Table(md.InterfaceImpl)
|
||||
for i := uint32(0); i < tableInterfaceImpl.RowCount(); i++ {
|
||||
var interfaceImpl types.InterfaceImpl
|
||||
if err := interfaceImpl.FromRow(tableInterfaceImpl.Row(i)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
classTd, err := interfaceImpl.ResolveClass(typeDef.Ctx())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if classTd.TypeNamespace+"."+classTd.TypeName != typeDef.TypeNamespace+"."+typeDef.TypeName {
|
||||
// not the class we are looking for
|
||||
continue
|
||||
}
|
||||
|
||||
if t, ok := interfaceImpl.Interface.Table(); ok && t == md.TypeSpec {
|
||||
// ignore type spec rows
|
||||
continue
|
||||
}
|
||||
|
||||
ifaceNS, ifaceName, err := typeDef.Ctx().ResolveTypeDefOrRefName(interfaceImpl.Interface)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
interfaces = append(interfaces, QualifiedID{Namespace: ifaceNS, Name: ifaceName})
|
||||
}
|
||||
|
||||
return interfaces, nil
|
||||
}
|
||||
|
||||
// Extends returns true if the type extends the given class
|
||||
func (typeDef *TypeDef) Extends(class string) (bool, error) {
|
||||
ns, name, err := typeDef.Ctx().ResolveTypeDefOrRefName(typeDef.TypeDef.Extends)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return ns+"."+name == class, nil
|
||||
}
|
||||
|
||||
// GetGenericParams returns the generic parameters of the type.
|
||||
func (typeDef *TypeDef) GetGenericParams() ([]*types.GenericParam, error) {
|
||||
params := make([]*types.GenericParam, 0)
|
||||
tableGenericParam := typeDef.Ctx().Table(md.GenericParam)
|
||||
for i := uint32(0); i < tableGenericParam.RowCount(); i++ {
|
||||
var genericParam types.GenericParam
|
||||
if err := genericParam.FromRow(tableGenericParam.Row(i)); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// - Owner: The owner of the Attribute must be the given typeDef
|
||||
if genericParamOwnerTable, _ := genericParam.Owner.Table(); genericParamOwnerTable != md.TypeDef {
|
||||
continue
|
||||
}
|
||||
|
||||
var ownerTypeDef types.TypeDef
|
||||
row, ok := genericParam.Owner.Row(typeDef.Ctx())
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if err := ownerTypeDef.FromRow(row); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// does the blob belong to the type we're looking for?
|
||||
if ownerTypeDef.TypeNamespace != typeDef.TypeNamespace || ownerTypeDef.TypeName != typeDef.TypeName {
|
||||
continue
|
||||
}
|
||||
|
||||
params = append(params, &genericParam)
|
||||
}
|
||||
if len(params) == 0 {
|
||||
return nil, fmt.Errorf("could not find generic params for type %s.%s", typeDef.TypeNamespace, typeDef.TypeName)
|
||||
}
|
||||
|
||||
return params, nil
|
||||
}
|
||||
|
||||
// IsInterface returns true if the type is an interface
|
||||
func (typeDef *TypeDef) IsInterface() bool {
|
||||
return typeDef.Flags.Interface()
|
||||
}
|
||||
|
||||
// IsEnum returns true if the type is an enum
|
||||
func (typeDef *TypeDef) IsEnum() bool {
|
||||
ok, err := typeDef.Extends("System.Enum")
|
||||
if err != nil {
|
||||
_ = level.Error(typeDef.logger).Log("msg", "error resolving type extends, all classes should extend at least System.Object", "err", err)
|
||||
return false
|
||||
}
|
||||
return ok
|
||||
}
|
||||
|
||||
// IsDelegate returns true if the type is a delegate
|
||||
func (typeDef *TypeDef) IsDelegate() bool {
|
||||
if !(typeDef.Flags.Public() && typeDef.Flags.Sealed()) {
|
||||
return false
|
||||
}
|
||||
|
||||
ok, err := typeDef.Extends("System.MulticastDelegate")
|
||||
if err != nil {
|
||||
_ = level.Error(typeDef.logger).Log("msg", "error resolving type extends, all classes should extend at least System.Object", "err", err)
|
||||
return false
|
||||
}
|
||||
|
||||
return ok
|
||||
}
|
||||
|
||||
// IsStruct returns true if the type is a struct
|
||||
func (typeDef *TypeDef) IsStruct() bool {
|
||||
ok, err := typeDef.Extends("System.ValueType")
|
||||
if err != nil {
|
||||
_ = level.Error(typeDef.logger).Log("msg", "error resolving type extends, all classes should extend at least System.Object", "err", err)
|
||||
return false
|
||||
}
|
||||
return ok
|
||||
}
|
||||
|
||||
// IsRuntimeClass returns true if the type is a runtime class
|
||||
func (typeDef *TypeDef) IsRuntimeClass() bool {
|
||||
// Flags: all runtime classes must carry the public, auto layout, class, and tdWindowsRuntime flags.
|
||||
return typeDef.Flags.Public() && typeDef.Flags.AutoLayout() && typeDef.Flags.Class() && typeDef.Flags&0x4000 != 0
|
||||
}
|
||||
|
||||
// GUID returns the GUID of the type.
|
||||
func (typeDef *TypeDef) GUID() (string, error) {
|
||||
blob, err := typeDef.GetAttributeWithType(AttributeTypeGUID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return guidBlobToString(blob)
|
||||
}
|
||||
|
||||
// guidBlobToString converts an array into the textual representation of a GUID
|
||||
func guidBlobToString(b types.Blob) (string, error) {
|
||||
// the guid is a blob of 20 bytes
|
||||
if len(b) != 20 {
|
||||
return "", fmt.Errorf("invalid GUID blob length: %d", len(b))
|
||||
}
|
||||
|
||||
// that starts with 0100
|
||||
if b[0] != 0x01 || b[1] != 0x00 {
|
||||
return "", fmt.Errorf("invalid GUID blob header, expected '0x01 0x00' but found '0x%02x 0x%02x'", b[0], b[1])
|
||||
}
|
||||
|
||||
// and ends with 0000
|
||||
if b[18] != 0x00 || b[19] != 0x00 {
|
||||
return "", fmt.Errorf("invalid GUID blob footer, expected '0x00 0x00' but found '0x%02x 0x%02x'", b[18], b[19])
|
||||
}
|
||||
|
||||
guid := b[2 : len(b)-2]
|
||||
// the string version has 5 parts separated by '-'
|
||||
return fmt.Sprintf("%08x-%04x-%04x-%04x-%04x%08x",
|
||||
// The first 3 are encoded as little endian
|
||||
uint32(guid[0])|uint32(guid[1])<<8|uint32(guid[2])<<16|uint32(guid[3])<<24,
|
||||
uint16(guid[4])|uint16(guid[5])<<8,
|
||||
uint16(guid[6])|uint16(guid[7])<<8,
|
||||
//the rest is not
|
||||
uint16(guid[8])<<8|uint16(guid[9]),
|
||||
uint16(guid[10])<<8|uint16(guid[11]),
|
||||
uint32(guid[12])<<24|uint32(guid[13])<<16|uint32(guid[14])<<8|uint32(guid[15])), nil
|
||||
}
|
61
internal/winmd/winmd.go
Normal file
61
internal/winmd/winmd.go
Normal file
@ -0,0 +1,61 @@
|
||||
package winmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"debug/pe"
|
||||
"embed"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/tdakkota/win32metadata/types"
|
||||
)
|
||||
|
||||
// Custom Attributes
|
||||
const (
|
||||
AttributeTypeGUID = "Windows.Foundation.Metadata.GuidAttribute"
|
||||
AttributeTypeExclusiveTo = "Windows.Foundation.Metadata.ExclusiveToAttribute"
|
||||
AttributeTypeStaticAttribute = "Windows.Foundation.Metadata.StaticAttribute"
|
||||
AttributeTypeActivatableAttribute = "Windows.Foundation.Metadata.ActivatableAttribute"
|
||||
AttributeTypeDefaultAttribute = "Windows.Foundation.Metadata.DefaultAttribute"
|
||||
AttributeTypeOverloadAttribute = "Windows.Foundation.Metadata.OverloadAttribute"
|
||||
)
|
||||
|
||||
// HasContext is a helper struct that holds the original context of a metadata element.
|
||||
type HasContext struct {
|
||||
originalCtx *types.Context
|
||||
}
|
||||
|
||||
// Ctx return the original context of the element.
|
||||
func (hctx *HasContext) Ctx() *types.Context {
|
||||
return hctx.originalCtx
|
||||
}
|
||||
|
||||
//go:embed metadata/*.winmd
|
||||
var files embed.FS
|
||||
|
||||
// allFiles returns all winmd files embedded in the binary.
|
||||
func allFiles() ([]fs.DirEntry, error) {
|
||||
return files.ReadDir("metadata")
|
||||
}
|
||||
|
||||
// open reads the given file and returns a pe.File instance.
|
||||
// The user should close the returned instance once he is done working with it.
|
||||
func open(path string) (*pe.File, error) {
|
||||
f, err := files.Open("metadata/" + path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() { _ = f.Close() }()
|
||||
|
||||
data, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pef, err := pe.NewFile(bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return pef, nil
|
||||
}
|
Reference in New Issue
Block a user