90 lines
2.1 KiB
Go
90 lines
2.1 KiB
Go
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
|
|
}
|