forked from jaypipes/pcidb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
parse.go
163 lines (157 loc) · 4.79 KB
/
parse.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
//
// 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
}