first commit
This commit is contained in:
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
|
||||
}
|
Reference in New Issue
Block a user