package main import "strconv" // packetFixed computes the minimum complete packet size. The first XML byte // occupies byte 1; the implicit sequence/length header follows that byte. func packetFixed(m *Module, n *Node, reply bool) (int, error) { off := 1 if n.Attr["no-sequence-number"] == "true" { off = 1 } for _, f := range n.Children { if f.Kind == "doc" { continue } size := 0 switch f.Kind { case "pad": if a := f.Attr["align"]; a != "" { align, _ := strconv.Atoi(a) size = (-off) & (align - 1) } else { size, _ = strconv.Atoi(f.Attr["bytes"]) } case "field", "exprfield": typ, err := lookup(m, f.Attr["type"]) if err != nil { return 0, err } size = typ.Size case "list": if len(f.Children) == 1 && f.Children[0].Kind == "value" { count, _ := strconv.Atoi(f.Children[0].Text) typ, err := lookup(m, f.Attr["type"]) if err != nil { return 0, err } size = count * typ.Size } else { goto done } default: return 0, f.fail("unsupported packet member %s", f.Kind) } off += size if off == 2 && n.Attr["no-sequence-number"] != "true" { if reply { off = 8 } else { off = 4 } } } done: if off < 32 { off = 32 } return off, nil } func packetSizeChecks(m *Module) error { for _, n := range m.Root.Children { if n.Kind == "event" || n.Kind == "eventcopy" { size := 32 if n.Kind == "event" { var err error size, err = packetFixed(m, n, false) if err != nil { return err } } if size != 32 { return n.fail("event fixed size %d, expected 32", size) } m.SizeChecks = append(m.SizeChecks, sizeCheck("event "+n.Attr["name"], size, 32)) } if n.Kind == "request" { for _, r := range n.Children { if r.Kind != "reply" { continue } size, err := packetFixed(m, r, true) if err != nil { return err } expected := 32 if m.Header == "xproto" { switch n.Attr["name"] { case "QueryKeymap": expected = 40 case "GetKeyboardControl": expected = 52 case "GetWindowAttributes": expected = 44 case "QueryFont", "ListFontsWithInfo": expected = 60 } } m.SizeChecks = append(m.SizeChecks, sizeCheck("reply "+n.Attr["name"], size, expected)) } } } return nil }