func NewFlashImage(buf []byte) (*FlashImage, error) {
	if len(buf) < FlashDescriptorLength {
		return nil, fmt.Errorf("flash Descriptor Map size too small: expected %v bytes, got %v",
			FlashDescriptorLength,
			len(buf),
		)
	}
	f := FlashImage{FlashSize: uint64(len(buf))}
	f.buf = make([]byte, len(buf))
	copy(f.buf, buf)
	f.IFD.buf = make([]byte, FlashDescriptorLength)
	copy(f.IFD.buf, buf[:FlashDescriptorLength])
	if err := f.IFD.ParseFlashDescriptor(); err != nil {
		return nil, err
	}
	frs := f.IFD.Region.FlashRegions[:]
	if !frs[RegionTypeBIOS].Valid() {
		return nil, fmt.Errorf("no BIOS region: invalid region parameters %v", frs[RegionTypeBIOS])
	}
	nr := int(f.IFD.DescriptorMap.NumberOfRegions)
	for i, fr := range frs {
		if nr != 0 && i >= nr {
			break
		}
		if !fr.Valid() {
			continue
		}
		if o := uint64(fr.BaseOffset()); o >= f.FlashSize {
			fmt.Printf("region %s (%d, %v) out of bounds: BaseOffset %#x, Flash size %#x, skipping...\n",
				flashRegionTypeNames[FlashRegionType(i)], i, fr, o, f.FlashSize)
			continue
		}
		if o := uint64(fr.EndOffset()); o > f.FlashSize {
			fmt.Printf("region %s (%d, %v) out of bounds: EndOffset %#x, Flash size %#x, skipping...\n",
				flashRegionTypeNames[FlashRegionType(i)], i, fr, o, f.FlashSize)
			continue
		}
		if c, ok := regionConstructors[FlashRegionType(i)]; ok {
			r, err := c(buf[fr.BaseOffset():fr.EndOffset()], &frs[i], FlashRegionType(i))
			if err != nil {
				return nil, err
			}
			f.Regions = append(f.Regions, MakeTyped(r))
		}
	}
	sort.Slice(f.Regions, func(i, j int) bool {
		ri := f.Regions[i].Value.(Region)
		rj := f.Regions[j].Value.(Region)
		return ri.FlashRegion().Base < rj.FlashRegion().Base
	})
	if err := f.fillRegionGaps(); err != nil {
		return nil, err
	}
	return &f, nil
}
NewFlashImage tries to create a FlashImage structure, and returns a FlashImage
and an error if any. This only works with images that operate in Descriptor
mode.
package uefi
import (
	"bytes"
	"encoding/hex"
	"fmt"
	"sort"
)
var (
	FlashSignature = []byte{0x5a, 0xa5, 0xf0, 0x0f}
)
const (
	FlashDescriptorLength = 0x1000
)
type FlashDescriptor struct {
	buf                []byte
	DescriptorMapStart uint
	RegionStart        uint
	MasterStart        uint
	DescriptorMap      *FlashDescriptorMap
	Region             *FlashRegionSection
	Master             *FlashMasterSection
	ExtractPath string
}
func FindSignature(buf []byte) (int, error) {
	if bytes.Equal(buf[16:16+len(FlashSignature)], FlashSignature) {
		return 20, nil
	}
	if bytes.Equal(buf[:len(FlashSignature)], FlashSignature) {
		return len(FlashSignature), nil
	}
	return -1, fmt.Errorf("flash signature not found: first 20 bytes are:\n%s",
		hex.Dump(buf[:20]))
}
func (fd *FlashDescriptor) Buf() []byte {
	return fd.buf
}
func (fd *FlashDescriptor) SetBuf(buf []byte) {
	fd.buf = buf
}
func (fd *FlashDescriptor) Apply(v Visitor) error {
	return v.Visit(fd)
}
func (fd *FlashDescriptor) ApplyChildren(v Visitor) error {
	return nil
}
func (fd *FlashDescriptor) ParseFlashDescriptor() error {
	if buflen := len(fd.buf); buflen != FlashDescriptorLength {
		return fmt.Errorf("flash descriptor length not %#x, was %#x", FlashDescriptorLength, buflen)
	}
	descriptorMapStart, err := FindSignature(fd.buf)
	if err != nil {
		return err
	}
	fd.DescriptorMapStart = uint(descriptorMapStart)
	desc, err := NewFlashDescriptorMap(fd.buf[fd.DescriptorMapStart:])
	if err != nil {
		return err
	}
	fd.DescriptorMap = desc
	fd.RegionStart = uint(fd.DescriptorMap.RegionBase) * 0x10
	region, err := NewFlashRegionSection(fd.buf[fd.RegionStart : fd.RegionStart+uint(FlashRegionSectionSize)])
	if err != nil {
		return err
	}
	fd.Region = region
	fd.MasterStart = uint(fd.DescriptorMap.MasterBase) * 0x10
	master, err := NewFlashMasterSection(fd.buf[fd.MasterStart : fd.MasterStart+uint(FlashMasterSectionSize)])
	if err != nil {
		return err
	}
	fd.Master = master
	return nil
}
type FlashImage struct {
	buf []byte
	IFD FlashDescriptor
	Regions []*TypedFirmware `json:",omitempty"`
	ExtractPath string
	FlashSize   uint64
}
func (f *FlashImage) Buf() []byte {
	return f.buf
}
func (f *FlashImage) SetBuf(buf []byte) {
	f.buf = buf
}
func (f *FlashImage) Apply(v Visitor) error {
	return v.Visit(f)
}
func (f *FlashImage) ApplyChildren(v Visitor) error {
	if err := f.IFD.Apply(v); err != nil {
		return err
	}
	for _, r := range f.Regions {
		if err := r.Value.Apply(v); err != nil {
			return err
		}
	}
	return nil
}
func (f *FlashImage) IsPCH() bool {
	return bytes.Equal(f.buf[16:16+len(FlashSignature)], FlashSignature)
}
func (f *FlashImage) FindSignature() (int, error) {
	return FindSignature(f.buf)
}
func (f *FlashImage) String() string {
	return fmt.Sprintf("FlashImage{Size=%v, Descriptor=%v, Region=%v, Master=%v}",
		len(f.buf),
		f.IFD.DescriptorMap.String(),
		f.IFD.Region.String(),
		f.IFD.Master.String(),
	)
}
func (f *FlashImage) fillRegionGaps() error {
	offset := uint64(FlashDescriptorLength)
	var newRegions []*TypedFirmware
	for _, t := range f.Regions {
		r, _ := t.Value.(Region)
		nextBase := uint64(r.FlashRegion().BaseOffset())
		if nextBase < offset {
			return fmt.Errorf("overlapping regions! region type %s overlaps with the previous region",
				r.Type().String())
		}
		if nextBase > offset {
			tempFR := &FlashRegion{Base: uint16(offset / RegionBlockSize),
				Limit: uint16(nextBase/RegionBlockSize) - 1}
			newRegions = append(newRegions, MakeTyped(&RawRegion{buf: f.buf[offset:nextBase],
				FRegion:    tempFR,
				RegionType: RegionTypeUnknown}))
		}
		offset = uint64(r.FlashRegion().EndOffset())
		newRegions = append(newRegions, MakeTyped(r))
	}
	if offset != f.FlashSize {
		tempFR := &FlashRegion{Base: uint16(offset / RegionBlockSize),
			Limit: uint16(f.FlashSize/RegionBlockSize) - 1}
		newRegions = append(newRegions, MakeTyped(&RawRegion{buf: f.buf[offset:f.FlashSize],
			FRegion:    tempFR,
			RegionType: RegionTypeUnknown}))
	}
	f.Regions = newRegions
	return nil
}