1package main
2
3import "strconv"
4
5// packetFixed computes the minimum complete packet size. The first XML byte
6// occupies byte 1; the implicit sequence/length header follows that byte.
7func packetFixed(m *Module, n *Node, reply bool) (int, error) {
8 off := 1
9 if n.Attr["no-sequence-number"] == "true" {
10 off = 1
11 }
12 for _, f := range n.Children {
13 if f.Kind == "doc" {
14 continue
15 }
16 size := 0
17 switch f.Kind {
18 case "pad":
19 if a := f.Attr["align"]; a != "" {
20 align, _ := strconv.Atoi(a)
21 size = (-off) & (align - 1)
22 } else {
23 size, _ = strconv.Atoi(f.Attr["bytes"])
24 }
25 case "field", "exprfield":
26 typ, err := lookup(m, f.Attr["type"])
27 if err != nil {
28 return 0, err
29 }
30 size = typ.Size
31 case "list":
32 if len(f.Children) == 1 && f.Children[0].Kind == "value" {
33 count, _ := strconv.Atoi(f.Children[0].Text)
34 typ, err := lookup(m, f.Attr["type"])
35 if err != nil {
36 return 0, err
37 }
38 size = count * typ.Size
39 } else {
40 goto done
41 }
42 default:
43 return 0, f.fail("unsupported packet member %s", f.Kind)
44 }
45 off += size
46 if off == 2 && n.Attr["no-sequence-number"] != "true" {
47 if reply {
48 off = 8
49 } else {
50 off = 4
51 }
52 }
53 }
54done:
55 if off < 32 {
56 off = 32
57 }
58 return off, nil
59}
60func packetSizeChecks(m *Module) error {
61 for _, n := range m.Root.Children {
62 if n.Kind == "event" || n.Kind == "eventcopy" {
63 size := 32
64 if n.Kind == "event" {
65 var err error
66 size, err = packetFixed(m, n, false)
67 if err != nil {
68 return err
69 }
70 }
71 if size != 32 {
72 return n.fail("event fixed size %d, expected 32", size)
73 }
74 m.SizeChecks = append(m.SizeChecks, sizeCheck("event "+n.Attr["name"], size, 32))
75 }
76 if n.Kind == "request" {
77 for _, r := range n.Children {
78 if r.Kind != "reply" {
79 continue
80 }
81 size, err := packetFixed(m, r, true)
82 if err != nil {
83 return err
84 }
85 expected := 32
86 if m.Header == "xproto" {
87 switch n.Attr["name"] {
88 case "QueryKeymap":
89 expected = 40
90 case "GetKeyboardControl":
91 expected = 52
92 case "GetWindowAttributes":
93 expected = 44
94 case "QueryFont", "ListFontsWithInfo":
95 expected = 60
96 }
97 }
98 m.SizeChecks = append(m.SizeChecks, sizeCheck("reply "+n.Attr["name"], size, expected))
99 }
100 }
101 }
102 return nil
103}