164 lines
4.8 KiB
Go
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
|
|
}
|