Files
scrutiny/vendor/github.com/jaypipes/pcidb/parse.go
T
2020-08-21 06:31:48 +00:00

164 lines
4.8 KiB
Go

//
// Use and distribution licensed under the Apache license version 2.
//
// See the COPYING file in the root project directory for full text.
//
package pcidb
import (
"bufio"
"strings"
)
func parseDBFile(db *PCIDB, scanner *bufio.Scanner) error {
inClassBlock := false
db.Classes = make(map[string]*Class, 20)
db.Vendors = make(map[string]*Vendor, 200)
db.Products = make(map[string]*Product, 1000)
subclasses := make([]*Subclass, 0)
progIfaces := make([]*ProgrammingInterface, 0)
var curClass *Class
var curSubclass *Subclass
var curProgIface *ProgrammingInterface
vendorProducts := make([]*Product, 0)
var curVendor *Vendor
var curProduct *Product
var curSubsystem *Product
productSubsystems := make([]*Product, 0)
for scanner.Scan() {
line := scanner.Text()
// skip comments and blank lines
if line == "" || strings.HasPrefix(line, "#") {
continue
}
lineBytes := []rune(line)
// Lines starting with an uppercase "C" indicate a PCI top-level class
// dbrmation block. These lines look like this:
//
// C 02 Network controller
if lineBytes[0] == 'C' {
if curClass != nil {
// finalize existing class because we found a new class block
curClass.Subclasses = subclasses
subclasses = make([]*Subclass, 0)
}
inClassBlock = true
classID := string(lineBytes[2:4])
className := string(lineBytes[6:])
curClass = &Class{
ID: classID,
Name: className,
Subclasses: subclasses,
}
db.Classes[curClass.ID] = curClass
continue
}
// Lines not beginning with an uppercase "C" or a TAB character
// indicate a top-level vendor dbrmation block. These lines look like
// this:
//
// 0a89 BREA Technologies Inc
if lineBytes[0] != '\t' {
if curVendor != nil {
// finalize existing vendor because we found a new vendor block
curVendor.Products = vendorProducts
vendorProducts = make([]*Product, 0)
}
inClassBlock = false
vendorID := string(lineBytes[0:4])
vendorName := string(lineBytes[6:])
curVendor = &Vendor{
ID: vendorID,
Name: vendorName,
Products: vendorProducts,
}
db.Vendors[curVendor.ID] = curVendor
continue
}
// Lines beginning with only a single TAB character are *either* a
// subclass OR are a device dbrmation block. If we're in a class
// block (i.e. the last parsed block header was for a PCI class), then
// we parse a subclass block. Otherwise, we parse a device dbrmation
// block.
//
// A subclass dbrmation block looks like this:
//
// \t00 Non-VGA unclassified device
//
// A device dbrmation block looks like this:
//
// \t0002 PCI to MCA Bridge
if len(lineBytes) > 1 && lineBytes[1] != '\t' {
if inClassBlock {
if curSubclass != nil {
// finalize existing subclass because we found a new subclass block
curSubclass.ProgrammingInterfaces = progIfaces
progIfaces = make([]*ProgrammingInterface, 0)
}
subclassID := string(lineBytes[1:3])
subclassName := string(lineBytes[5:])
curSubclass = &Subclass{
ID: subclassID,
Name: subclassName,
ProgrammingInterfaces: progIfaces,
}
subclasses = append(subclasses, curSubclass)
} else {
if curProduct != nil {
// finalize existing product because we found a new product block
curProduct.Subsystems = productSubsystems
productSubsystems = make([]*Product, 0)
}
productID := string(lineBytes[1:5])
productName := string(lineBytes[7:])
productKey := curVendor.ID + productID
curProduct = &Product{
VendorID: curVendor.ID,
ID: productID,
Name: productName,
}
vendorProducts = append(vendorProducts, curProduct)
db.Products[productKey] = curProduct
}
} else {
// Lines beginning with two TAB characters are *either* a subsystem
// (subdevice) OR are a programming interface for a PCI device
// subclass. If we're in a class block (i.e. the last parsed block
// header was for a PCI class), then we parse a programming
// interface block, otherwise we parse a subsystem block.
//
// A programming interface block looks like this:
//
// \t\t00 UHCI
//
// A subsystem block looks like this:
//
// \t\t0e11 4091 Smart Array 6i
if inClassBlock {
progIfaceID := string(lineBytes[2:4])
progIfaceName := string(lineBytes[6:])
curProgIface = &ProgrammingInterface{
ID: progIfaceID,
Name: progIfaceName,
}
progIfaces = append(progIfaces, curProgIface)
} else {
vendorID := string(lineBytes[2:6])
subsystemID := string(lineBytes[7:11])
subsystemName := string(lineBytes[13:])
curSubsystem = &Product{
VendorID: vendorID,
ID: subsystemID,
Name: subsystemName,
}
productSubsystems = append(productSubsystems, curSubsystem)
}
}
}
return nil
}