detached d08e097

feat(xtgen): decode replies as zero-copy views with list iterators

Generate <Req>Reply value views and Parse<Req>Reply for every reply in all
nine packages: fixed-offset getters from reply byte 0, []byte views for byte
lists, <Elem>List views for scalar and fixed-struct lists, and <Struct>View
plus <Struct>Iter for variable-size structs. Parse validates the full length
once; list getters recompute running offsets from fixed fields.

Capture eleven reply goldens from Xvfb through the socketpair tee, emit a
FuzzParse<Req>Reply per reply seeded from the goldens, and assert zero
allocations for parse, getters and list iteration.
commit
d08e09740c9dfda20d9091dd6605af9de66a9a00
author
brice · · 2026-10-22 07:09 UTC
parent
017e663
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
checks
4/4
36 files · +5795 -12
A bigreq/replies_fuzz_test.go +21 -0
@@ -0,0 +1,21 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package bigreq
3+
4+import "testing"
5+
6+func FuzzParseEnableReply(f *testing.F) {
7+ f.Add(make([]byte, 32))
8+ f.Fuzz(func(t *testing.T, raw []byte) {
9+ r, ok := ParseEnableReply(raw)
10+ if !ok {
11+ if len(raw) >= 32 {
12+ t.Fatal("rejected a complete fixed-size reply")
13+ }
14+ return
15+ }
16+ if len(r.Raw()) != len(raw) {
17+ t.Fatal("Raw must return the parsed bytes")
18+ }
19+ _ = r.MaximumRequestLength()
20+ })
21+}
A bigreq/replies_generated.go +21 -0
@@ -0,0 +1,21 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package bigreq
3+
4+import "encoding/binary"
5+
6+// EnableReply is a zero-copy view over a Enable reply; offsets count from reply byte 0.
7+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
8+type EnableReply struct{ raw []byte }
9+
10+// ParseEnableReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
11+func ParseEnableReply(raw []byte) (EnableReply, bool) {
12+ if len(raw) < 32 {
13+ return EnableReply{}, false
14+ }
15+ r := EnableReply{raw: raw}
16+ return r, true
17+}
18+func (r EnableReply) Raw() []byte { return r.raw }
19+func (r EnableReply) MaximumRequestLength() uint32 {
20+ return uint32(binary.LittleEndian.Uint32(r.raw[8:]))
21+}
M cmd/xtgen/main.go +3 -0
@@ -32,6 +32,9 @@ func main() {
3232 if err == nil {
3333 err = emitRequests(modules)
3434 }
35+ if err == nil {
36+ err = emitReplies(modules)
37+ }
3538 if err != nil {
3639 fmt.Fprintln(os.Stderr, err)
3740 os.Exit(1)
A cmd/xtgen/replies.go +554 -0
@@ -0,0 +1,554 @@
1+package main
2+
3+import (
4+ "fmt"
5+ "path/filepath"
6+ "sort"
7+ "strconv"
8+ "strings"
9+)
10+
11+// member is one wire member of a decoded container (reply or variable struct
12+// view). Static is the offset from the container's byte 0, or -1 when it
13+// follows a variable-length list and must be recomputed from earlier members.
14+type member struct {
15+ XName, Method, Kind, GoType string
16+ Elem string // annotated element Go type for list views
17+ Type *Type
18+ Size, Align, Static int
19+ Count *Node
20+ ListKind string // bytes, scalar, struct, iter
21+}
22+
23+// container is the lowered layout shared by replies and variable struct views.
24+type container struct {
25+ Name, Recv string
26+ Members []member
27+ Fixed int // minimum byte length (static prefix)
28+ Dynamic int // index of the first variable list, -1 when none
29+ Reply bool
30+ Module *Module
31+}
32+
33+const replyLifetime = "It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep."
34+
35+func isByteElem(xml string) bool {
36+ return xml == "void" || xml == "BYTE" || xml == "CARD8" || xml == "char"
37+}
38+
39+func annotatedType(m *Module, n *Node, typ *Type) (string, error) {
40+ goType := qualified(m, typ.Module, typ.GoType)
41+ for _, attr := range []string{"enum", "mask"} {
42+ if name := n.Attr[attr]; name != "" {
43+ e, owner := findEnum(m, name)
44+ if e == nil {
45+ return "", n.fail("unknown %s %s", attr, name)
46+ }
47+ goType = qualified(m, owner, e.Name)
48+ }
49+ }
50+ return goType, nil
51+}
52+
53+// elemName names the per-package list view for an element type.
54+func elemName(goType string) string {
55+ if i := strings.LastIndex(goType, "."); i >= 0 {
56+ goType = goType[i+1:]
57+ }
58+ return strings.ToUpper(goType[:1]) + goType[1:]
59+}
60+
61+// buildContainer lowers XML members. Replies start at byte 1 (the first XML
62+// member occupies the header data byte) and continue at byte 8.
63+func buildContainer(m *Module, name, recv string, nodes []*Node, reply bool, reserved string) (*container, error) {
64+ c := &container{Name: name, Recv: recv, Reply: reply, Dynamic: -1, Module: m}
65+ off := 0
66+ if reply {
67+ off = 1
68+ }
69+ first := true
70+ methods := map[string]bool{}
71+ for _, n := range nodes {
72+ if n.Kind == "doc" {
73+ continue
74+ }
75+ mem := member{XName: n.Attr["name"], Kind: n.Kind, Static: off}
76+ if c.Dynamic >= 0 {
77+ mem.Static = -1
78+ }
79+ switch n.Kind {
80+ case "pad":
81+ if a := n.Attr["align"]; a != "" {
82+ mem.Align, _ = strconv.Atoi(a)
83+ if c.Dynamic < 0 {
84+ mem.Size = (-off) & (mem.Align - 1)
85+ }
86+ } else {
87+ mem.Size, _ = strconv.Atoi(n.Attr["bytes"])
88+ }
89+ case "field", "list":
90+ typ, err := lookup(m, n.Attr["type"])
91+ if err != nil {
92+ return nil, n.fail("%v", err)
93+ }
94+ mem.Type = typ
95+ mem.Method = goName(mem.XName)
96+ if contains(reserved, mem.Method) {
97+ mem.Method += "_"
98+ }
99+ if methods[mem.Method] {
100+ return nil, n.fail("duplicate getter %s", mem.Method)
101+ }
102+ methods[mem.Method] = true
103+ elem, err := annotatedType(m, n, typ)
104+ if err != nil {
105+ return nil, err
106+ }
107+ mem.Elem = elem
108+ if n.Kind == "field" {
109+ if typ.Variable {
110+ return nil, n.fail("variable-size field outside a list is unsupported")
111+ }
112+ mem.GoType = elem
113+ mem.Size = typ.Size
114+ break
115+ }
116+ if len(n.Children) != 1 {
117+ return nil, n.fail("reply-side list requires a length expression")
118+ }
119+ mem.Count = n.Children[0]
120+ switch {
121+ case isByteElem(n.Attr["type"]):
122+ mem.ListKind, mem.GoType = "bytes", "[]byte"
123+ case typ.Variable:
124+ if typ.Size == 0 {
125+ return nil, n.fail("variable struct %s has an empty fixed prefix", typ.Name)
126+ }
127+ mem.ListKind, mem.GoType = "iter", qualified(m, typ.Module, typ.GoType+"Iter")
128+ case isScalar(typ):
129+ mem.ListKind, mem.GoType = "scalar", elemName(elem)+"List"
130+ default:
131+ mem.ListKind, mem.GoType = "struct", elemName(elem)+"List"
132+ }
133+ constant := mem.Count.Kind == "value" && !typ.Variable
134+ if constant {
135+ count, _ := strconv.Atoi(mem.Count.Text)
136+ mem.Size = count * typ.Size
137+ } else if c.Dynamic < 0 {
138+ c.Dynamic = len(c.Members)
139+ }
140+ default:
141+ return nil, n.fail("unsupported %s member %s", map[bool]string{true: "reply", false: "struct"}[reply], n.Kind)
142+ }
143+ if reply && first {
144+ if mem.Size != 1 {
145+ return nil, n.fail("first reply member must occupy the header data byte")
146+ }
147+ off = 8
148+ first = false
149+ c.Members = append(c.Members, mem)
150+ continue
151+ }
152+ first = false
153+ if c.Dynamic < 0 {
154+ off += mem.Size
155+ }
156+ c.Members = append(c.Members, mem)
157+ }
158+ if c.Dynamic >= 0 {
159+ c.Fixed = c.Members[c.Dynamic].Static
160+ } else {
161+ c.Fixed = off
162+ }
163+ return c, nil
164+}
165+
166+// ref renders a field reference as a getter call on the receiver. Replies may
167+// refer to the implicit header length word.
168+func (c *container) ref(s string) string {
169+ for _, mem := range c.Members {
170+ if mem.Kind == "field" && mem.XName == s {
171+ return "int(" + c.Recv + "." + mem.Method + "())"
172+ }
173+ }
174+ if c.Reply && s == "length" {
175+ return "int(binary.LittleEndian.Uint32(" + c.Recv + ".raw[4:]))"
176+ }
177+ return "<unresolved " + s + ">"
178+}
179+
180+func (c *container) count(mem member) (string, error) {
181+ s, err := renderExpr(mem.Count, c.ref, c.Module)
182+ if err != nil {
183+ return "", err
184+ }
185+ if strings.Contains(s, "<unresolved") {
186+ return "", mem.Count.fail("list length references an unknown field")
187+ }
188+ return s, nil
189+}
190+
191+// advance emits code moving off past member i. With fail != "" every step is
192+// bounds-checked against raw.
193+func (c *container) advance(b *strings.Builder, i int, fail string) error {
194+ mem := c.Members[i]
195+ raw := c.Recv + ".raw"
196+ switch mem.Kind {
197+ case "pad":
198+ if mem.Align > 0 {
199+ fmt.Fprintf(b, "off=(off+%d)&^%d;", mem.Align-1, mem.Align-1)
200+ } else {
201+ fmt.Fprintf(b, "off+=%d;", mem.Size)
202+ }
203+ case "field":
204+ fmt.Fprintf(b, "off+=%d;", mem.Size)
205+ case "list":
206+ n, err := c.count(mem)
207+ if err != nil {
208+ return err
209+ }
210+ if mem.ListKind == "iter" {
211+ fmt.Fprintf(b, "{ n:=%s;", n)
212+ if fail != "" {
213+ fmt.Fprintf(b, "if off>len(%s) || n<0 || n>len(%s) { %s };", raw, raw, fail)
214+ }
215+ fmt.Fprintf(b, "it:=%s(%s[off:],n); for it.Next() { off+=it.Value().Size() };", qualified(c.Module, mem.Type.Module, "New"+mem.Type.GoType+"Iter"), raw)
216+ if fail != "" {
217+ fmt.Fprintf(b, "if it.Err() { %s };", fail)
218+ }
219+ b.WriteString("};")
220+ return nil
221+ }
222+ fmt.Fprintf(b, "{ n:=%s;", n)
223+ if fail != "" {
224+ fmt.Fprintf(b, "if n<0 || n>len(%s) { %s };", raw, fail)
225+ }
226+ fmt.Fprintf(b, "off+=n*%d };", mem.Type.Size)
227+ if fail != "" {
228+ fmt.Fprintf(b, "if off>len(%s) { %s };", raw, fail)
229+ }
230+ }
231+ return nil
232+}
233+
234+// offset emits statements leaving member i's offset in off.
235+func (c *container) offset(b *strings.Builder, i int) error {
236+ if c.Members[i].Static >= 0 {
237+ fmt.Fprintf(b, "off:=%d;", c.Members[i].Static)
238+ return nil
239+ }
240+ fmt.Fprintf(b, "off:=%d;", c.Fixed)
241+ for j := c.Dynamic; j < i; j++ {
242+ if err := c.advance(b, j, ""); err != nil {
243+ return err
244+ }
245+ }
246+ return nil
247+}
248+
249+// validate emits the full-length walk used by Parse and Iter.Next.
250+func (c *container) validate(b *strings.Builder, fail string) error {
251+ if c.Dynamic < 0 {
252+ return nil
253+ }
254+ fmt.Fprintf(b, "off:=%d;", c.Fixed)
255+ for j := c.Dynamic; j < len(c.Members); j++ {
256+ if err := c.advance(b, j, fail); err != nil {
257+ return err
258+ }
259+ }
260+ fmt.Fprintf(b, "if off>len(%s.raw) { %s };", c.Recv, fail)
261+ return nil
262+}
263+
264+// getters emits one method per field and list.
265+func (c *container) getters(b *strings.Builder, typ string, lists map[string]string) error {
266+ r := c.Recv
267+ for i, mem := range c.Members {
268+ if mem.Kind == "pad" {
269+ continue
270+ }
271+ fmt.Fprintf(b, "func (%s %s) %s() %s {", r, typ, mem.Method, mem.GoType)
272+ static := mem.Static >= 0
273+ at := fmt.Sprintf("%s.raw[%d:]", r, mem.Static)
274+ if !static {
275+ if err := c.offset(b, i); err != nil {
276+ return err
277+ }
278+ at = r + ".raw[off:]"
279+ }
280+ if mem.Kind == "field" {
281+ if isScalar(mem.Type) {
282+ fmt.Fprintf(b, "return %s };\n", getScalar(mem.Type, mem.GoType, at))
283+ } else {
284+ fmt.Fprintf(b, "return %s(%s) };\n", qualified(c.Module, mem.Type.Module, "Get"+mem.Type.GoType), at)
285+ }
286+ continue
287+ }
288+ if static {
289+ fmt.Fprintf(b, "off:=%d;", mem.Static)
290+ }
291+ n, err := c.count(mem)
292+ if err != nil {
293+ return err
294+ }
295+ switch mem.ListKind {
296+ case "iter":
297+ fmt.Fprintf(b, "return %s(%s.raw[off:],%s) };\n", qualified(c.Module, mem.Type.Module, "New"+mem.Type.GoType+"Iter"), r, n)
298+ case "bytes":
299+ fmt.Fprintf(b, "end:=off+%s; return %s.raw[off:end:end] };\n", n, r)
300+ default:
301+ fmt.Fprintf(b, "end:=off+(%s)*%d; return %s{b:%s.raw[off:end:end]} };\n", n, mem.Type.Size, mem.GoType, r)
302+ lists[mem.GoType] = listDecl(c.Module, mem.GoType, mem.Elem, mem.Type)
303+ }
304+ }
305+ return nil
306+}
307+
308+func listDecl(m *Module, name, goType string, elem *Type) string {
309+ var b strings.Builder
310+ fmt.Fprintf(&b, "// %s is a borrowed view over a wire list of %s. %s\n", name, goType, "It shares the lifetime of the bytes it was taken from; copy what you keep.")
311+ fmt.Fprintf(&b, "type %s struct { b []byte };\n", name)
312+ fmt.Fprintf(&b, "func (l %s) Len() int { return len(l.b)/%d };\n", name, elem.Size)
313+ src := fmt.Sprintf("l.b[i*%d:]", elem.Size)
314+ if isScalar(elem) {
315+ fmt.Fprintf(&b, "func (l %s) At(i int) %s { return %s };\n", name, goType, getScalar(elem, goType, src))
316+ } else {
317+ fmt.Fprintf(&b, "func (l %s) At(i int) %s { return %s(%s) };\n", name, goType, qualified(m, elem.Module, "Get"+elem.GoType), src)
318+ }
319+ return b.String()
320+}
321+
322+type replyIR struct {
323+ Req string
324+ C *container
325+}
326+
327+func resolveReplies(m *Module) ([]replyIR, []*container, error) {
328+ var replies []replyIR
329+ for _, n := range m.Root.Children {
330+ if n.Kind != "request" {
331+ continue
332+ }
333+ for _, r := range n.Children {
334+ if r.Kind != "reply" {
335+ continue
336+ }
337+ name := goName(n.Attr["name"])
338+ for _, s := range []string{name + "Reply", "Parse" + name + "Reply"} {
339+ if err := m.claim(s, r); err != nil {
340+ return nil, nil, err
341+ }
342+ }
343+ c, err := buildContainer(m, name+"Reply", "r", r.Children, true, "Raw")
344+ if err != nil {
345+ return nil, nil, err
346+ }
347+ replies = append(replies, replyIR{Req: name, C: c})
348+ }
349+ }
350+ var views []*container
351+ for _, t := range m.Types {
352+ if t.Kind != "struct" || !t.Variable {
353+ continue
354+ }
355+ for _, s := range []string{t.GoType + "View", t.GoType + "Iter", "New" + t.GoType + "Iter"} {
356+ if err := m.claim(s, t.Node); err != nil {
357+ return nil, nil, err
358+ }
359+ }
360+ c, err := buildContainer(m, t.GoType+"View", "v", t.Node.Children, false, "Raw Size")
361+ if err != nil {
362+ return nil, nil, err
363+ }
364+ views = append(views, c)
365+ }
366+ return replies, views, nil
367+}
368+
369+func replyDecl(r replyIR, lists map[string]string) (string, error) {
370+ c := r.C
371+ var b strings.Builder
372+ fmt.Fprintf(&b, "// %s is a zero-copy view over a %s reply; offsets count from reply byte 0.\n// %s\n", c.Name, r.Req, replyLifetime)
373+ fmt.Fprintf(&b, "type %s struct { raw []byte };\n", c.Name)
374+ fmt.Fprintf(&b, "// Parse%s validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.\n", c.Name)
375+ fmt.Fprintf(&b, "func Parse%s(raw []byte) (%s, bool) {", c.Name, c.Name)
376+ fixed := max(c.Fixed, 32)
377+ fmt.Fprintf(&b, "if len(raw)<%d { return %s{}, false };", fixed, c.Name)
378+ fmt.Fprintf(&b, "r:=%s{raw:raw};", c.Name)
379+ if err := c.validate(&b, "return "+c.Name+"{}, false"); err != nil {
380+ return "", err
381+ }
382+ b.WriteString("return r, true };\n")
383+ fmt.Fprintf(&b, "func (r %s) Raw() []byte { return r.raw };\n", c.Name)
384+ if err := c.getters(&b, c.Name, lists); err != nil {
385+ return "", err
386+ }
387+ return b.String(), nil
388+}
389+
390+func viewDecl(c *container, lists map[string]string) (string, error) {
391+ base := strings.TrimSuffix(c.Name, "View")
392+ iter := base + "Iter"
393+ var b strings.Builder
394+ fmt.Fprintf(&b, "// %s is a zero-copy view over one wire-encoded %s, yielded by %s.\n// It shares the lifetime of the bytes it was taken from (for replies: until the Handler callback returns). Copy what you keep.\n", c.Name, base, iter)
395+ fmt.Fprintf(&b, "type %s struct { raw []byte };\n", c.Name)
396+ fmt.Fprintf(&b, "func (v %s) Raw() []byte { return v.raw };\n", c.Name)
397+ fmt.Fprintf(&b, "// Size is the element's wire size, including trailing alignment.\nfunc (v %s) Size() int { return len(v.raw) };\n", c.Name)
398+ // size%s returns the element's wire size at the start of p, -1 when malformed.
399+ fmt.Fprintf(&b, "func size%s(p []byte) int { if len(p)<%d { return -1 }; v:=%s{raw:p}; _=v;", base, c.Fixed, c.Name)
400+ if c.Dynamic < 0 {
401+ fmt.Fprintf(&b, "return %d };\n", c.Fixed)
402+ } else {
403+ if err := c.validate(&b, "return -1"); err != nil {
404+ return "", err
405+ }
406+ b.WriteString("return off };\n")
407+ }
408+ if err := c.getters(&b, c.Name, lists); err != nil {
409+ return "", err
410+ }
411+ fmt.Fprintf(&b, "// %s walks n consecutive %s elements; Err reports a malformed length.\n// It shares the lifetime of the bytes it walks.\n", iter, base)
412+ fmt.Fprintf(&b, "type %s struct { b []byte; n int; v %s; err bool };\n", iter, c.Name)
413+ fmt.Fprintf(&b, "// New%s iterates n elements encoded at the start of b.\nfunc New%s(b []byte, n int) %s { return %s{b:b, n:n} };\n", iter, iter, iter, iter)
414+ fmt.Fprintf(&b, "func (it *%s) Next() bool { if it.n<=0 || it.err { return false }; s:=size%s(it.b); if s<0 { it.err=true; it.n=0; return false }; it.v=%s{raw:it.b[:s:s]}; it.b=it.b[s:]; it.n--; return true };\n", iter, base, c.Name)
415+ fmt.Fprintf(&b, "func (it *%s) Value() %s { return it.v };\n", iter, c.Name)
416+ fmt.Fprintf(&b, "func (it *%s) Err() bool { return it.err };\n", iter)
417+ return b.String(), nil
418+}
419+
420+// touch emits fuzz statements calling every getter and walking every list,
421+// recursing into variable struct views.
422+func touch(b *strings.Builder, c *container, expr string, depth int, all map[*Type]*container, failIter string) {
423+ for _, mem := range c.Members {
424+ switch {
425+ case mem.Kind == "field":
426+ fmt.Fprintf(b, "_ = %s.%s();", expr, mem.Method)
427+ case mem.Kind == "list" && mem.ListKind == "bytes":
428+ fmt.Fprintf(b, "_ = len(%s.%s());", expr, mem.Method)
429+ case mem.Kind == "list" && mem.ListKind == "iter":
430+ it := fmt.Sprintf("it%d", depth)
431+ fmt.Fprintf(b, "{ %s := %s.%s(); for %s.Next() {", it, expr, mem.Method, it)
432+ if child := all[mem.Type]; child != nil {
433+ touch(b, child, it+".Value()", depth+1, all, failIter)
434+ }
435+ fmt.Fprintf(b, "}; if %s.Err() { %s } };", it, failIter)
436+ case mem.Kind == "list":
437+ l := fmt.Sprintf("l%d", depth)
438+ fmt.Fprintf(b, "{ %s := %s.%s(); for i := 0; i < %s.Len(); i++ { _ = %s.At(i) } };", l, expr, mem.Method, l, l)
439+ }
440+ }
441+}
442+
443+func emitReplies(modules []*Module) error {
444+ type pending struct {
445+ m *Module
446+ replies []replyIR
447+ views []*container
448+ }
449+ var all []pending
450+ views := map[*Type]*container{}
451+ for _, m := range modules {
452+ replies, vs, err := resolveReplies(m)
453+ if err != nil {
454+ return err
455+ }
456+ for _, v := range vs {
457+ for _, t := range m.Types {
458+ if t.GoType+"View" == v.Name {
459+ views[t] = v
460+ }
461+ }
462+ }
463+ all = append(all, pending{m, replies, vs})
464+ }
465+ for _, p := range all {
466+ m := p.m
467+ lists := map[string]string{}
468+ var decls []string
469+ for _, r := range p.replies {
470+ d, err := replyDecl(r, lists)
471+ if err != nil {
472+ return err
473+ }
474+ decls = append(decls, d)
475+ }
476+ for _, v := range p.views {
477+ d, err := viewDecl(v, lists)
478+ if err != nil {
479+ return err
480+ }
481+ decls = append(decls, d)
482+ }
483+ var names []string
484+ for name := range lists {
485+ if err := m.claim(name, m.Root); err != nil {
486+ return err
487+ }
488+ names = append(names, name)
489+ }
490+ sort.Strings(names)
491+ for _, name := range names {
492+ decls = append(decls, lists[name])
493+ }
494+ if len(decls) == 0 {
495+ continue
496+ }
497+ decls = append([]string{importsFor(m, strings.Join(decls, "\n"))}, decls...)
498+ data := struct {
499+ Pkg string
500+ Decls []string
501+ }{Pkg: m.Pkg, Decls: decls}
502+ if err := writeTemplate(filepath.Join(m.Pkg, "replies_generated.go"), "replies", data); err != nil {
503+ return err
504+ }
505+ if err := emitReplyFuzz(m, p.replies, views); err != nil {
506+ return err
507+ }
508+ }
509+ return nil
510+}
511+
512+// emitReplyFuzz writes FuzzParse<Req>Reply for every reply. Seeds are the
513+// zero-filled fixed prefix plus any captured goldens <Req>*.reply.hex.
514+func emitReplyFuzz(m *Module, replies []replyIR, views map[*Type]*container) error {
515+ var decls []string
516+ usesGolden := false
517+ for _, r := range replies {
518+ var b strings.Builder
519+ c := r.C
520+ fmt.Fprintf(&b, "func FuzzParse%s(f *testing.F) {\n", c.Name)
521+ fmt.Fprintf(&b, "f.Add(make([]byte, %d));\n", (max(c.Fixed, 32)+3)&^3)
522+ goldens, _ := filepath.Glob(filepath.Join("testdata/golden", m.Pkg, r.Req+"*.reply.hex"))
523+ sort.Strings(goldens)
524+ for _, g := range goldens {
525+ base := filepath.Base(g)
526+ if strings.TrimSuffix(base, ".reply.hex") != r.Req && !startsUpper(strings.TrimPrefix(strings.TrimSuffix(base, ".reply.hex"), r.Req)) {
527+ continue
528+ }
529+ usesGolden = true
530+ fmt.Fprintf(&b, "if raw, err := xtest.LoadHex(%q); err != nil { f.Fatal(err) } else { f.Add(raw) };\n", "../"+filepath.ToSlash(g))
531+ }
532+ fmt.Fprintf(&b, "f.Fuzz(func(t *testing.T, raw []byte) {\nr, ok := Parse%s(raw);\nif !ok {", c.Name)
533+ if c.Dynamic < 0 {
534+ fmt.Fprintf(&b, "if len(raw) >= %d { t.Fatal(\"rejected a complete fixed-size reply\") };", max(c.Fixed, 32))
535+ }
536+ b.WriteString("return };\n")
537+ b.WriteString("if len(r.Raw()) != len(raw) { t.Fatal(\"Raw must return the parsed bytes\") };\n")
538+ touch(&b, c, "r", 0, views, `t.Fatal("iterator error after successful Parse")`)
539+ b.WriteString("\n})\n}\n")
540+ decls = append(decls, b.String())
541+ }
542+ imports := "import \"testing\""
543+ if usesGolden {
544+ imports += "\nimport \"bnema.dev/xturbo/internal/xtest\""
545+ }
546+ decls = append([]string{imports}, decls...)
547+ data := struct {
548+ Pkg string
549+ Decls []string
550+ }{Pkg: m.Pkg, Decls: decls}
551+ return writeTemplate(filepath.Join(m.Pkg, "replies_fuzz_test.go"), "replies", data)
552+}
553+
554+func startsUpper(s string) bool { return s != "" && s[0] >= 'A' && s[0] <= 'Z' }
A cmd/xtgen/replies_test.go +70 -0
@@ -0,0 +1,70 @@
1+package main
2+
3+import "testing"
4+
5+// TestReplyLayouts checks reply containers against the independent packet-size
6+// walker and pins list-view classification for representative replies.
7+func TestReplyLayouts(t *testing.T) {
8+ kinds := map[string]map[string]string{
9+ "xproto.GetPropertyReply": {"Value": "bytes"},
10+ "xproto.QueryTreeReply": {"Children": "scalar"},
11+ "xproto.ListExtensionsReply": {"Names": "iter"},
12+ "xproto.QueryFontReply": {"Properties": "struct", "CharInfos": "struct"},
13+ "xproto.ListHostsReply": {"Hosts": "iter"},
14+ "render.QueryPictFormatsReply": {"Formats": "struct", "Screens": "iter", "Subpixels": "scalar"},
15+ "xfixes.GetCursorImageAndNameReply": {"CursorImage": "scalar", "Name": "bytes"},
16+ }
17+ for _, m := range testModules(t) {
18+ replies, _, err := resolveReplies(m)
19+ if err != nil {
20+ t.Fatal(err)
21+ }
22+ for _, r := range replies {
23+ var node *Node
24+ for _, n := range m.Root.Children {
25+ if n.Kind == "request" && goName(n.Attr["name"]) == r.Req {
26+ for _, c := range n.Children {
27+ if c.Kind == "reply" {
28+ node = c
29+ }
30+ }
31+ }
32+ }
33+ want, err := packetFixed(m, node, true)
34+ if err != nil {
35+ t.Fatal(err)
36+ }
37+ if got := max(r.C.Fixed, 32); got != want {
38+ t.Errorf("%s.%s fixed %d, packet walker %d", m.Pkg, r.C.Name, got, want)
39+ }
40+ for _, mem := range r.C.Members {
41+ if exp, ok := kinds[m.Pkg+"."+r.C.Name]; ok && mem.Kind == "list" {
42+ if exp[mem.Method] != mem.ListKind {
43+ t.Errorf("%s.%s.%s kind %s want %s", m.Pkg, r.C.Name, mem.Method, mem.ListKind, exp[mem.Method])
44+ }
45+ delete(exp, mem.Method)
46+ }
47+ }
48+ }
49+ }
50+ for name, rest := range kinds {
51+ if len(rest) != 0 {
52+ t.Errorf("%s: unchecked lists %v", name, rest)
53+ }
54+ }
55+}
56+
57+func TestReplyReservedGetter(t *testing.T) {
58+ m := &Module{Pkg: "x", Symbols: map[string]*Type{}, Names: map[string]*Node{}}
59+ nodes := []*Node{
60+ {Kind: "pad", Attr: map[string]string{"bytes": "1"}},
61+ {Kind: "field", Attr: map[string]string{"name": "raw", "type": "CARD32"}},
62+ }
63+ c, err := buildContainer(m, "XReply", "r", nodes, true, "Raw")
64+ if err != nil {
65+ t.Fatal(err)
66+ }
67+ if c.Members[1].Method != "Raw_" || c.Members[1].Static != 8 || c.Fixed != 12 {
68+ t.Fatalf("%+v", c.Members[1])
69+ }
70+}
A cmd/xtgen/templates/replies.tmpl +5 -0
@@ -0,0 +1,5 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package {{.Pkg}}
3+{{range .Decls}}
4+{{.}}
5+{{end}}
A composite/replies_fuzz_test.go +39 -0
@@ -0,0 +1,39 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package composite
3+
4+import "testing"
5+
6+func FuzzParseQueryVersionReply(f *testing.F) {
7+ f.Add(make([]byte, 32))
8+ f.Fuzz(func(t *testing.T, raw []byte) {
9+ r, ok := ParseQueryVersionReply(raw)
10+ if !ok {
11+ if len(raw) >= 32 {
12+ t.Fatal("rejected a complete fixed-size reply")
13+ }
14+ return
15+ }
16+ if len(r.Raw()) != len(raw) {
17+ t.Fatal("Raw must return the parsed bytes")
18+ }
19+ _ = r.MajorVersion()
20+ _ = r.MinorVersion()
21+ })
22+}
23+
24+func FuzzParseGetOverlayWindowReply(f *testing.F) {
25+ f.Add(make([]byte, 32))
26+ f.Fuzz(func(t *testing.T, raw []byte) {
27+ r, ok := ParseGetOverlayWindowReply(raw)
28+ if !ok {
29+ if len(raw) >= 32 {
30+ t.Fatal("rejected a complete fixed-size reply")
31+ }
32+ return
33+ }
34+ if len(r.Raw()) != len(raw) {
35+ t.Fatal("Raw must return the parsed bytes")
36+ }
37+ _ = r.OverlayWin()
38+ })
39+}
A composite/replies_generated.go +42 -0
@@ -0,0 +1,42 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package composite
3+
4+import "bnema.dev/xturbo/xproto"
5+import "encoding/binary"
6+
7+// QueryVersionReply is a zero-copy view over a QueryVersion reply; offsets count from reply byte 0.
8+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
9+type QueryVersionReply struct{ raw []byte }
10+
11+// ParseQueryVersionReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
12+func ParseQueryVersionReply(raw []byte) (QueryVersionReply, bool) {
13+ if len(raw) < 32 {
14+ return QueryVersionReply{}, false
15+ }
16+ r := QueryVersionReply{raw: raw}
17+ return r, true
18+}
19+func (r QueryVersionReply) Raw() []byte { return r.raw }
20+func (r QueryVersionReply) MajorVersion() uint32 {
21+ return uint32(binary.LittleEndian.Uint32(r.raw[8:]))
22+}
23+func (r QueryVersionReply) MinorVersion() uint32 {
24+ return uint32(binary.LittleEndian.Uint32(r.raw[12:]))
25+}
26+
27+// GetOverlayWindowReply is a zero-copy view over a GetOverlayWindow reply; offsets count from reply byte 0.
28+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
29+type GetOverlayWindowReply struct{ raw []byte }
30+
31+// ParseGetOverlayWindowReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
32+func ParseGetOverlayWindowReply(raw []byte) (GetOverlayWindowReply, bool) {
33+ if len(raw) < 32 {
34+ return GetOverlayWindowReply{}, false
35+ }
36+ r := GetOverlayWindowReply{raw: raw}
37+ return r, true
38+}
39+func (r GetOverlayWindowReply) Raw() []byte { return r.raw }
40+func (r GetOverlayWindowReply) OverlayWin() xproto.Window {
41+ return xproto.Window(binary.LittleEndian.Uint32(r.raw[8:]))
42+}
A ge/replies_fuzz_test.go +22 -0
@@ -0,0 +1,22 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package ge
3+
4+import "testing"
5+
6+func FuzzParseQueryVersionReply(f *testing.F) {
7+ f.Add(make([]byte, 32))
8+ f.Fuzz(func(t *testing.T, raw []byte) {
9+ r, ok := ParseQueryVersionReply(raw)
10+ if !ok {
11+ if len(raw) >= 32 {
12+ t.Fatal("rejected a complete fixed-size reply")
13+ }
14+ return
15+ }
16+ if len(r.Raw()) != len(raw) {
17+ t.Fatal("Raw must return the parsed bytes")
18+ }
19+ _ = r.MajorVersion()
20+ _ = r.MinorVersion()
21+ })
22+}
A ge/replies_generated.go +24 -0
@@ -0,0 +1,24 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package ge
3+
4+import "encoding/binary"
5+
6+// QueryVersionReply is a zero-copy view over a QueryVersion reply; offsets count from reply byte 0.
7+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
8+type QueryVersionReply struct{ raw []byte }
9+
10+// ParseQueryVersionReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
11+func ParseQueryVersionReply(raw []byte) (QueryVersionReply, bool) {
12+ if len(raw) < 32 {
13+ return QueryVersionReply{}, false
14+ }
15+ r := QueryVersionReply{raw: raw}
16+ return r, true
17+}
18+func (r QueryVersionReply) Raw() []byte { return r.raw }
19+func (r QueryVersionReply) MajorVersion() uint16 {
20+ return uint16(binary.LittleEndian.Uint16(r.raw[8:]))
21+}
22+func (r QueryVersionReply) MinorVersion() uint16 {
23+ return uint16(binary.LittleEndian.Uint16(r.raw[10:]))
24+}
M internal/xtest/README.md +10 -1
@@ -15,7 +15,9 @@ The captured target is the root window; XFIXES's major opcode is negotiated.
1515 Tests read target/opcode from the fixture, not a hard-coded server assignment.
1616 No runtime Conn is needed at this phase.
1717
18-Replies, events and runtime integration belong to their subsequent tasks.
18+The same run also writes reply goldens (`<Name>.reply.hex`): the server's
19+response to each reference request, read back through the tee. Events and
20+runtime integration belong to their subsequent tasks.
1921
2022 T2.4 adds InternAtom, ChangeProperty and XRes QueryClientIds. A GetProperty
2123 read-back validates the property contents. XRes's major opcode is negotiated;
@@ -29,3 +31,10 @@ values, and fences void requests with a successful reply (any preceding error
2931 fails capture). RENDER's opcode and the root visual's picture format are queried
3032 from Xvfb. Tests reuse only server-assigned resource/format IDs from fixtures;
3133 mask bits, values and ordering remain independent expected inputs.
34+
35+T2.6 keeps the replies to QueryExtension, xfixes QueryVersion, GetGeometry,
36+InternAtom, GetProperty, res QueryClientIds and render QueryPictFormats, and
37+adds GetWindowAttributes (child window), QueryTree (root), an unset WM_NAME
38+GetProperty (zero-length value) and ListExtensions (variable STR list). These
39+reply-only requests use opcodes outside the request-golden classifier.
40+Generated `FuzzParse*Reply` targets seed from every matching reply golden.
M internal/xtest/capture_test.go +52 -11
@@ -111,6 +111,17 @@ func TestCaptureRequests(t *testing.T) {
111111 // Query XFIXES dynamically rather than assuming a server-specific major opcode.
112112 query := []byte{98, 0, 4, 0, 6, 0, 0, 0, 'X', 'F', 'I', 'X', 'E', 'S', 0, 0}
113113 write(query)
114+ // Server bytes reach the client through the same tee; keep named replies as
115+ // reply goldens (reply byte 0 through 32+4*length).
116+ replies := map[string][]byte{}
117+ keep := func(name string, p []byte) []byte {
118+ t.Helper()
119+ if p[0] != 1 {
120+ t.Fatalf("%s: expected a reply, got %x", name, p)
121+ }
122+ replies[name] = p
123+ return p
124+ }
114125 packet := func() []byte {
115126 t.Helper()
116127 head := make([]byte, 32)
@@ -122,7 +133,7 @@ func TestCaptureRequests(t *testing.T) {
122133 }
123134 return head
124135 }
125- ext := packet()
136+ ext := keep("xproto/QueryExtension", packet())
126137 if ext[0] != 1 || ext[8] != 1 {
127138 t.Fatalf("XFIXES unavailable: %x", ext)
128139 }
@@ -132,7 +143,7 @@ func TestCaptureRequests(t *testing.T) {
132143 version[2] = 3
133144 binary.LittleEndian.PutUint32(version[4:], 6)
134145 write(version)
135- reply := packet()
146+ reply := keep("xfixes/QueryVersion", packet())
136147 if reply[0] != 1 {
137148 t.Fatalf("QueryVersion failed: %x", reply)
138149 }
@@ -144,7 +155,7 @@ func TestCaptureRequests(t *testing.T) {
144155 geometry := append([]byte(nil), mapReq...)
145156 geometry[0] = 14
146157 write(geometry)
147- geom := packet()
158+ geom := keep("xproto/GetGeometry", packet())
148159 if geom[0] != 1 || binary.LittleEndian.Uint16(geom[2:]) != 4 {
149160 t.Fatalf("MapWindow/GetGeometry rejected: %x", geom)
150161 }
@@ -153,7 +164,7 @@ func TestCaptureRequests(t *testing.T) {
153164 // byte expressions and fixed-struct lists with independently assembled bytes.
154165 intern := []byte{16, 0, 4, 0, 7, 0, 0, 0, 'X', 'T', 'U', 'R', 'B', 'O', '_', 0}
155166 write(intern)
156- atomReply := packet()
167+ atomReply := keep("xproto/InternAtom", packet())
157168 if atomReply[0] != 1 {
158169 t.Fatalf("InternAtom: %x", atomReply)
159170 }
@@ -176,7 +187,7 @@ func TestCaptureRequests(t *testing.T) {
176187 binary.LittleEndian.PutUint32(get[8:], atom)
177188 binary.LittleEndian.PutUint32(get[20:], 1)
178189 write(get)
179- got := packet()
190+ got := keep("xproto/GetProperty", packet())
180191 if got[0] != 1 || string(got[32:35]) != "abc" {
181192 t.Fatalf("ChangeProperty: %x", got)
182193 }
@@ -204,9 +215,7 @@ func TestCaptureRequests(t *testing.T) {
204215 binary.LittleEndian.PutUint32(ids[4:], 1)
205216 binary.LittleEndian.PutUint32(ids[12:], 1)
206217 write(ids)
207- if p := packet(); p[0] != 1 {
208- t.Fatalf("QueryClientIds: %x", p)
209- }
218+ keep("res/QueryClientIds", packet())
210219 // Value-list reference packets are assembled independently, including mask-bit
211220 // ordering. Two sibling windows allow all seven ConfigureWindow bits to be
212221 // exercised legally. A final reply fences all void requests and exposes errors.
@@ -257,7 +266,7 @@ func TestCaptureRequests(t *testing.T) {
257266 }
258267 renderMajor := renderExt[9]
259268 write([]byte{renderMajor, 1, 1, 0}) // QueryPictFormats
260- formatsReply := packet()
269+ formatsReply := keep("render/QueryPictFormats", packet())
261270 if formatsReply[0] != 1 {
262271 t.Fatalf("QueryPictFormats: %x", formatsReply)
263272 }
@@ -296,6 +305,28 @@ func TestCaptureRequests(t *testing.T) {
296305 if p := packet(); p[0] != 1 {
297306 t.Fatalf("CreatePicture rejected: %x", p)
298307 }
308+ // Reply-only captures. Opcodes 3, 15, 20 and 99 are not request goldens, so
309+ // the request-stream classifier below is unaffected.
310+ attrs := make([]byte, 8)
311+ attrs[0], attrs[2] = 3, 2
312+ binary.LittleEndian.PutUint32(attrs[4:], child)
313+ write(attrs)
314+ keep("xproto/GetWindowAttributes", packet())
315+ tree := make([]byte, 8)
316+ tree[0], tree[2] = 15, 2
317+ binary.LittleEndian.PutUint32(tree[4:], root)
318+ write(tree)
319+ keep("xproto/QueryTree", packet())
320+ // WM_NAME is unset on a fresh Xvfb root: a zero-length GetProperty reply.
321+ empty := make([]byte, 24)
322+ empty[0], empty[2] = 20, 6
323+ binary.LittleEndian.PutUint32(empty[4:], root)
324+ binary.LittleEndian.PutUint32(empty[8:], 39)
325+ binary.LittleEndian.PutUint32(empty[20:], 1)
326+ write(empty)
327+ keep("xproto/GetPropertyEmpty", packet())
328+ write([]byte{99, 0, 1, 0}) // ListExtensions: variable STR iterator
329+ keep("xproto/ListExtensions", packet())
299330 // Closing the client drains the request direction; wait before inspecting tee.
300331 client.Close()
301332 select {
@@ -348,8 +379,18 @@ func TestCaptureRequests(t *testing.T) {
348379 }
349380 requests = requests[size:]
350381 }
351- if len(captured) != 12 {
352- t.Fatal("missing captured requests")
382+ if len(captured) != 12 || len(replies) != 11 {
383+ t.Fatal("missing captured requests or replies")
384+ }
385+ for name, p := range replies {
386+ path := filepath.Join("../../testdata/golden", name+".reply.hex")
387+ if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
388+ t.Fatal(err)
389+ }
390+ text := "# source: Xvfb reply via raw socketpair tee to an independent reference request\n# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace\n" + hex.EncodeToString(p) + "\n"
391+ if err := os.WriteFile(path, []byte(text), 0644); err != nil {
392+ t.Fatal(err)
393+ }
353394 }
354395 for name, p := range captured {
355396 path := filepath.Join("../../testdata/golden", name+".req.hex")
A render/replies_fuzz_test.go +135 -0
@@ -0,0 +1,135 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package render
3+
4+import "testing"
5+import "bnema.dev/xturbo/internal/xtest"
6+
7+func FuzzParseQueryVersionReply(f *testing.F) {
8+ f.Add(make([]byte, 32))
9+ f.Fuzz(func(t *testing.T, raw []byte) {
10+ r, ok := ParseQueryVersionReply(raw)
11+ if !ok {
12+ if len(raw) >= 32 {
13+ t.Fatal("rejected a complete fixed-size reply")
14+ }
15+ return
16+ }
17+ if len(r.Raw()) != len(raw) {
18+ t.Fatal("Raw must return the parsed bytes")
19+ }
20+ _ = r.MajorVersion()
21+ _ = r.MinorVersion()
22+ })
23+}
24+
25+func FuzzParseQueryPictFormatsReply(f *testing.F) {
26+ f.Add(make([]byte, 32))
27+ if raw, err := xtest.LoadHex("../testdata/golden/render/QueryPictFormats.reply.hex"); err != nil {
28+ f.Fatal(err)
29+ } else {
30+ f.Add(raw)
31+ }
32+ f.Fuzz(func(t *testing.T, raw []byte) {
33+ r, ok := ParseQueryPictFormatsReply(raw)
34+ if !ok {
35+ return
36+ }
37+ if len(r.Raw()) != len(raw) {
38+ t.Fatal("Raw must return the parsed bytes")
39+ }
40+ _ = r.NumFormats()
41+ _ = r.NumScreens()
42+ _ = r.NumDepths()
43+ _ = r.NumVisuals()
44+ _ = r.NumSubpixel()
45+ {
46+ l0 := r.Formats()
47+ for i := 0; i < l0.Len(); i++ {
48+ _ = l0.At(i)
49+ }
50+ }
51+ {
52+ it0 := r.Screens()
53+ for it0.Next() {
54+ _ = it0.Value().NumDepths()
55+ _ = it0.Value().Fallback()
56+ {
57+ it1 := it0.Value().Depths()
58+ for it1.Next() {
59+ _ = it1.Value().Depth()
60+ _ = it1.Value().NumVisuals()
61+ {
62+ l2 := it1.Value().Visuals()
63+ for i := 0; i < l2.Len(); i++ {
64+ _ = l2.At(i)
65+ }
66+ }
67+ }
68+ if it1.Err() {
69+ t.Fatal("iterator error after successful Parse")
70+ }
71+ }
72+ }
73+ if it0.Err() {
74+ t.Fatal("iterator error after successful Parse")
75+ }
76+ }
77+ {
78+ l0 := r.Subpixels()
79+ for i := 0; i < l0.Len(); i++ {
80+ _ = l0.At(i)
81+ }
82+ }
83+ })
84+}
85+
86+func FuzzParseQueryPictIndexValuesReply(f *testing.F) {
87+ f.Add(make([]byte, 32))
88+ f.Fuzz(func(t *testing.T, raw []byte) {
89+ r, ok := ParseQueryPictIndexValuesReply(raw)
90+ if !ok {
91+ return
92+ }
93+ if len(r.Raw()) != len(raw) {
94+ t.Fatal("Raw must return the parsed bytes")
95+ }
96+ _ = r.NumValues()
97+ {
98+ l0 := r.Values()
99+ for i := 0; i < l0.Len(); i++ {
100+ _ = l0.At(i)
101+ }
102+ }
103+ })
104+}
105+
106+func FuzzParseQueryFiltersReply(f *testing.F) {
107+ f.Add(make([]byte, 32))
108+ f.Fuzz(func(t *testing.T, raw []byte) {
109+ r, ok := ParseQueryFiltersReply(raw)
110+ if !ok {
111+ return
112+ }
113+ if len(r.Raw()) != len(raw) {
114+ t.Fatal("Raw must return the parsed bytes")
115+ }
116+ _ = r.NumAliases()
117+ _ = r.NumFilters()
118+ {
119+ l0 := r.Aliases()
120+ for i := 0; i < l0.Len(); i++ {
121+ _ = l0.At(i)
122+ }
123+ }
124+ {
125+ it0 := r.Filters()
126+ for it0.Next() {
127+ _ = it0.Value().NameLen()
128+ _ = len(it0.Value().Name())
129+ }
130+ if it0.Err() {
131+ t.Fatal("iterator error after successful Parse")
132+ }
133+ }
134+ })
135+}
A render/replies_generated.go +380 -0
@@ -0,0 +1,380 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package render
3+
4+import "bnema.dev/xturbo/xproto"
5+import "encoding/binary"
6+
7+// QueryVersionReply is a zero-copy view over a QueryVersion reply; offsets count from reply byte 0.
8+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
9+type QueryVersionReply struct{ raw []byte }
10+
11+// ParseQueryVersionReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
12+func ParseQueryVersionReply(raw []byte) (QueryVersionReply, bool) {
13+ if len(raw) < 32 {
14+ return QueryVersionReply{}, false
15+ }
16+ r := QueryVersionReply{raw: raw}
17+ return r, true
18+}
19+func (r QueryVersionReply) Raw() []byte { return r.raw }
20+func (r QueryVersionReply) MajorVersion() uint32 {
21+ return uint32(binary.LittleEndian.Uint32(r.raw[8:]))
22+}
23+func (r QueryVersionReply) MinorVersion() uint32 {
24+ return uint32(binary.LittleEndian.Uint32(r.raw[12:]))
25+}
26+
27+// QueryPictFormatsReply is a zero-copy view over a QueryPictFormats reply; offsets count from reply byte 0.
28+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
29+type QueryPictFormatsReply struct{ raw []byte }
30+
31+// ParseQueryPictFormatsReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
32+func ParseQueryPictFormatsReply(raw []byte) (QueryPictFormatsReply, bool) {
33+ if len(raw) < 32 {
34+ return QueryPictFormatsReply{}, false
35+ }
36+ r := QueryPictFormatsReply{raw: raw}
37+ off := 32
38+ {
39+ n := int(r.NumFormats())
40+ if n < 0 || n > len(r.raw) {
41+ return QueryPictFormatsReply{}, false
42+ }
43+ off += n * 28
44+ }
45+ if off > len(r.raw) {
46+ return QueryPictFormatsReply{}, false
47+ }
48+ {
49+ n := int(r.NumScreens())
50+ if off > len(r.raw) || n < 0 || n > len(r.raw) {
51+ return QueryPictFormatsReply{}, false
52+ }
53+ it := NewPictscreenIter(r.raw[off:], n)
54+ for it.Next() {
55+ off += it.Value().Size()
56+ }
57+ if it.Err() {
58+ return QueryPictFormatsReply{}, false
59+ }
60+ }
61+ {
62+ n := int(r.NumSubpixel())
63+ if n < 0 || n > len(r.raw) {
64+ return QueryPictFormatsReply{}, false
65+ }
66+ off += n * 4
67+ }
68+ if off > len(r.raw) {
69+ return QueryPictFormatsReply{}, false
70+ }
71+ if off > len(r.raw) {
72+ return QueryPictFormatsReply{}, false
73+ }
74+ return r, true
75+}
76+func (r QueryPictFormatsReply) Raw() []byte { return r.raw }
77+func (r QueryPictFormatsReply) NumFormats() uint32 {
78+ return uint32(binary.LittleEndian.Uint32(r.raw[8:]))
79+}
80+func (r QueryPictFormatsReply) NumScreens() uint32 {
81+ return uint32(binary.LittleEndian.Uint32(r.raw[12:]))
82+}
83+func (r QueryPictFormatsReply) NumDepths() uint32 {
84+ return uint32(binary.LittleEndian.Uint32(r.raw[16:]))
85+}
86+func (r QueryPictFormatsReply) NumVisuals() uint32 {
87+ return uint32(binary.LittleEndian.Uint32(r.raw[20:]))
88+}
89+func (r QueryPictFormatsReply) NumSubpixel() uint32 {
90+ return uint32(binary.LittleEndian.Uint32(r.raw[24:]))
91+}
92+func (r QueryPictFormatsReply) Formats() PictforminfoList {
93+ off := 32
94+ end := off + (int(r.NumFormats()))*28
95+ return PictforminfoList{b: r.raw[off:end:end]}
96+}
97+func (r QueryPictFormatsReply) Screens() PictscreenIter {
98+ off := 32
99+ {
100+ n := int(r.NumFormats())
101+ off += n * 28
102+ }
103+ return NewPictscreenIter(r.raw[off:], int(r.NumScreens()))
104+}
105+func (r QueryPictFormatsReply) Subpixels() SubPixelList {
106+ off := 32
107+ {
108+ n := int(r.NumFormats())
109+ off += n * 28
110+ }
111+ {
112+ n := int(r.NumScreens())
113+ it := NewPictscreenIter(r.raw[off:], n)
114+ for it.Next() {
115+ off += it.Value().Size()
116+ }
117+ }
118+ end := off + (int(r.NumSubpixel()))*4
119+ return SubPixelList{b: r.raw[off:end:end]}
120+}
121+
122+// QueryPictIndexValuesReply is a zero-copy view over a QueryPictIndexValues reply; offsets count from reply byte 0.
123+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
124+type QueryPictIndexValuesReply struct{ raw []byte }
125+
126+// ParseQueryPictIndexValuesReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
127+func ParseQueryPictIndexValuesReply(raw []byte) (QueryPictIndexValuesReply, bool) {
128+ if len(raw) < 32 {
129+ return QueryPictIndexValuesReply{}, false
130+ }
131+ r := QueryPictIndexValuesReply{raw: raw}
132+ off := 32
133+ {
134+ n := int(r.NumValues())
135+ if n < 0 || n > len(r.raw) {
136+ return QueryPictIndexValuesReply{}, false
137+ }
138+ off += n * 12
139+ }
140+ if off > len(r.raw) {
141+ return QueryPictIndexValuesReply{}, false
142+ }
143+ if off > len(r.raw) {
144+ return QueryPictIndexValuesReply{}, false
145+ }
146+ return r, true
147+}
148+func (r QueryPictIndexValuesReply) Raw() []byte { return r.raw }
149+func (r QueryPictIndexValuesReply) NumValues() uint32 {
150+ return uint32(binary.LittleEndian.Uint32(r.raw[8:]))
151+}
152+func (r QueryPictIndexValuesReply) Values() IndexvalueList {
153+ off := 32
154+ end := off + (int(r.NumValues()))*12
155+ return IndexvalueList{b: r.raw[off:end:end]}
156+}
157+
158+// QueryFiltersReply is a zero-copy view over a QueryFilters reply; offsets count from reply byte 0.
159+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
160+type QueryFiltersReply struct{ raw []byte }
161+
162+// ParseQueryFiltersReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
163+func ParseQueryFiltersReply(raw []byte) (QueryFiltersReply, bool) {
164+ if len(raw) < 32 {
165+ return QueryFiltersReply{}, false
166+ }
167+ r := QueryFiltersReply{raw: raw}
168+ off := 32
169+ {
170+ n := int(r.NumAliases())
171+ if n < 0 || n > len(r.raw) {
172+ return QueryFiltersReply{}, false
173+ }
174+ off += n * 2
175+ }
176+ if off > len(r.raw) {
177+ return QueryFiltersReply{}, false
178+ }
179+ {
180+ n := int(r.NumFilters())
181+ if off > len(r.raw) || n < 0 || n > len(r.raw) {
182+ return QueryFiltersReply{}, false
183+ }
184+ it := xproto.NewStrIter(r.raw[off:], n)
185+ for it.Next() {
186+ off += it.Value().Size()
187+ }
188+ if it.Err() {
189+ return QueryFiltersReply{}, false
190+ }
191+ }
192+ if off > len(r.raw) {
193+ return QueryFiltersReply{}, false
194+ }
195+ return r, true
196+}
197+func (r QueryFiltersReply) Raw() []byte { return r.raw }
198+func (r QueryFiltersReply) NumAliases() uint32 { return uint32(binary.LittleEndian.Uint32(r.raw[8:])) }
199+func (r QueryFiltersReply) NumFilters() uint32 { return uint32(binary.LittleEndian.Uint32(r.raw[12:])) }
200+func (r QueryFiltersReply) Aliases() Uint16List {
201+ off := 32
202+ end := off + (int(r.NumAliases()))*2
203+ return Uint16List{b: r.raw[off:end:end]}
204+}
205+func (r QueryFiltersReply) Filters() xproto.StrIter {
206+ off := 32
207+ {
208+ n := int(r.NumAliases())
209+ off += n * 2
210+ }
211+ return xproto.NewStrIter(r.raw[off:], int(r.NumFilters()))
212+}
213+
214+// PictdepthView is a zero-copy view over one wire-encoded Pictdepth, yielded by PictdepthIter.
215+// It shares the lifetime of the bytes it was taken from (for replies: until the Handler callback returns). Copy what you keep.
216+type PictdepthView struct{ raw []byte }
217+
218+func (v PictdepthView) Raw() []byte { return v.raw }
219+
220+// Size is the element's wire size, including trailing alignment.
221+func (v PictdepthView) Size() int { return len(v.raw) }
222+func sizePictdepth(p []byte) int {
223+ if len(p) < 8 {
224+ return -1
225+ }
226+ v := PictdepthView{raw: p}
227+ _ = v
228+ off := 8
229+ {
230+ n := int(v.NumVisuals())
231+ if n < 0 || n > len(v.raw) {
232+ return -1
233+ }
234+ off += n * 8
235+ }
236+ if off > len(v.raw) {
237+ return -1
238+ }
239+ if off > len(v.raw) {
240+ return -1
241+ }
242+ return off
243+}
244+func (v PictdepthView) Depth() uint8 { return uint8(v.raw[0:][0]) }
245+func (v PictdepthView) NumVisuals() uint16 { return uint16(binary.LittleEndian.Uint16(v.raw[2:])) }
246+func (v PictdepthView) Visuals() PictvisualList {
247+ off := 8
248+ end := off + (int(v.NumVisuals()))*8
249+ return PictvisualList{b: v.raw[off:end:end]}
250+}
251+
252+// PictdepthIter walks n consecutive Pictdepth elements; Err reports a malformed length.
253+// It shares the lifetime of the bytes it walks.
254+type PictdepthIter struct {
255+ b []byte
256+ n int
257+ v PictdepthView
258+ err bool
259+}
260+
261+// NewPictdepthIter iterates n elements encoded at the start of b.
262+func NewPictdepthIter(b []byte, n int) PictdepthIter { return PictdepthIter{b: b, n: n} }
263+func (it *PictdepthIter) Next() bool {
264+ if it.n <= 0 || it.err {
265+ return false
266+ }
267+ s := sizePictdepth(it.b)
268+ if s < 0 {
269+ it.err = true
270+ it.n = 0
271+ return false
272+ }
273+ it.v = PictdepthView{raw: it.b[:s:s]}
274+ it.b = it.b[s:]
275+ it.n--
276+ return true
277+}
278+func (it *PictdepthIter) Value() PictdepthView { return it.v }
279+func (it *PictdepthIter) Err() bool { return it.err }
280+
281+// PictscreenView is a zero-copy view over one wire-encoded Pictscreen, yielded by PictscreenIter.
282+// It shares the lifetime of the bytes it was taken from (for replies: until the Handler callback returns). Copy what you keep.
283+type PictscreenView struct{ raw []byte }
284+
285+func (v PictscreenView) Raw() []byte { return v.raw }
286+
287+// Size is the element's wire size, including trailing alignment.
288+func (v PictscreenView) Size() int { return len(v.raw) }
289+func sizePictscreen(p []byte) int {
290+ if len(p) < 8 {
291+ return -1
292+ }
293+ v := PictscreenView{raw: p}
294+ _ = v
295+ off := 8
296+ {
297+ n := int(v.NumDepths())
298+ if off > len(v.raw) || n < 0 || n > len(v.raw) {
299+ return -1
300+ }
301+ it := NewPictdepthIter(v.raw[off:], n)
302+ for it.Next() {
303+ off += it.Value().Size()
304+ }
305+ if it.Err() {
306+ return -1
307+ }
308+ }
309+ if off > len(v.raw) {
310+ return -1
311+ }
312+ return off
313+}
314+func (v PictscreenView) NumDepths() uint32 { return uint32(binary.LittleEndian.Uint32(v.raw[0:])) }
315+func (v PictscreenView) Fallback() Pictformat {
316+ return Pictformat(binary.LittleEndian.Uint32(v.raw[4:]))
317+}
318+func (v PictscreenView) Depths() PictdepthIter {
319+ off := 8
320+ return NewPictdepthIter(v.raw[off:], int(v.NumDepths()))
321+}
322+
323+// PictscreenIter walks n consecutive Pictscreen elements; Err reports a malformed length.
324+// It shares the lifetime of the bytes it walks.
325+type PictscreenIter struct {
326+ b []byte
327+ n int
328+ v PictscreenView
329+ err bool
330+}
331+
332+// NewPictscreenIter iterates n elements encoded at the start of b.
333+func NewPictscreenIter(b []byte, n int) PictscreenIter { return PictscreenIter{b: b, n: n} }
334+func (it *PictscreenIter) Next() bool {
335+ if it.n <= 0 || it.err {
336+ return false
337+ }
338+ s := sizePictscreen(it.b)
339+ if s < 0 {
340+ it.err = true
341+ it.n = 0
342+ return false
343+ }
344+ it.v = PictscreenView{raw: it.b[:s:s]}
345+ it.b = it.b[s:]
346+ it.n--
347+ return true
348+}
349+func (it *PictscreenIter) Value() PictscreenView { return it.v }
350+func (it *PictscreenIter) Err() bool { return it.err }
351+
352+// IndexvalueList is a borrowed view over a wire list of Indexvalue. It shares the lifetime of the bytes it was taken from; copy what you keep.
353+type IndexvalueList struct{ b []byte }
354+
355+func (l IndexvalueList) Len() int { return len(l.b) / 12 }
356+func (l IndexvalueList) At(i int) Indexvalue { return GetIndexvalue(l.b[i*12:]) }
357+
358+// PictforminfoList is a borrowed view over a wire list of Pictforminfo. It shares the lifetime of the bytes it was taken from; copy what you keep.
359+type PictforminfoList struct{ b []byte }
360+
361+func (l PictforminfoList) Len() int { return len(l.b) / 28 }
362+func (l PictforminfoList) At(i int) Pictforminfo { return GetPictforminfo(l.b[i*28:]) }
363+
364+// PictvisualList is a borrowed view over a wire list of Pictvisual. It shares the lifetime of the bytes it was taken from; copy what you keep.
365+type PictvisualList struct{ b []byte }
366+
367+func (l PictvisualList) Len() int { return len(l.b) / 8 }
368+func (l PictvisualList) At(i int) Pictvisual { return GetPictvisual(l.b[i*8:]) }
369+
370+// SubPixelList is a borrowed view over a wire list of SubPixel. It shares the lifetime of the bytes it was taken from; copy what you keep.
371+type SubPixelList struct{ b []byte }
372+
373+func (l SubPixelList) Len() int { return len(l.b) / 4 }
374+func (l SubPixelList) At(i int) SubPixel { return SubPixel(binary.LittleEndian.Uint32(l.b[i*4:])) }
375+
376+// Uint16List is a borrowed view over a wire list of uint16. It shares the lifetime of the bytes it was taken from; copy what you keep.
377+type Uint16List struct{ b []byte }
378+
379+func (l Uint16List) Len() int { return len(l.b) / 2 }
380+func (l Uint16List) At(i int) uint16 { return uint16(binary.LittleEndian.Uint16(l.b[i*2:])) }
A replies_test.go +304 -0
@@ -0,0 +1,304 @@
1+package xturbo_test
2+
3+import (
4+ "bytes"
5+ "encoding/binary"
6+ "testing"
7+
8+ "bnema.dev/xturbo/internal/xtest"
9+ "bnema.dev/xturbo/render"
10+ "bnema.dev/xturbo/res"
11+ "bnema.dev/xturbo/xfixes"
12+ "bnema.dev/xturbo/xproto"
13+)
14+
15+func loadReply(t testing.TB, name string) []byte {
16+ t.Helper()
17+ raw, err := xtest.LoadHex("testdata/golden/" + name + ".reply.hex")
18+ if err != nil {
19+ t.Fatal(err)
20+ }
21+ if raw[0] != 1 || len(raw) != 32+4*int(binary.LittleEndian.Uint32(raw[4:])) {
22+ t.Fatalf("%s: not a framed reply", name)
23+ }
24+ return raw
25+}
26+
27+// Expected values are independent of the generated code: they follow from the
28+// capture script (window geometry, written property, ConfigureWindow state)
29+// or are read from the raw golden at protocol-spec offsets.
30+func TestReplyGoldens(t *testing.T) {
31+ u32 := func(raw []byte, off int) uint32 { return binary.LittleEndian.Uint32(raw[off:]) }
32+ t.Run("xproto/GetGeometry", func(t *testing.T) {
33+ raw := loadReply(t, "xproto/GetGeometry")
34+ r, ok := xproto.ParseGetGeometryReply(raw)
35+ if !ok || r.Depth() != 24 || r.Root() != xproto.Window(u32(raw, 8)) || r.X() != 0 || r.Y() != 0 ||
36+ r.Width() != 800 || r.Height() != 600 || r.BorderWidth() != 0 || !bytes.Equal(r.Raw(), raw) {
37+ t.Fatalf("decoded %+v", r)
38+ }
39+ })
40+ t.Run("xproto/QueryTree", func(t *testing.T) {
41+ raw := loadReply(t, "xproto/QueryTree")
42+ r, ok := xproto.ParseQueryTreeReply(raw)
43+ if !ok || r.Root() != xproto.Window(u32(raw, 8)) || r.Parent() != xproto.WindowNone || r.ChildrenLen() != 2 {
44+ t.Fatal("fixed fields")
45+ }
46+ c := r.Children()
47+ // Stacking order bottom-to-top: the sibling was created before the child.
48+ if c.Len() != 2 || c.At(0)&0x1fffff != 2 || c.At(1)&0x1fffff != 1 || c.At(0)&^0x1fffff != c.At(1)&^0x1fffff {
49+ t.Fatalf("children %x %x", c.At(0), c.At(1))
50+ }
51+ })
52+ t.Run("xproto/GetWindowAttributes", func(t *testing.T) {
53+ raw := loadReply(t, "xproto/GetWindowAttributes")
54+ r, ok := xproto.ParseGetWindowAttributesReply(raw)
55+ if !ok || r.BackingStore() != xproto.BackingStoreNotUseful || r.Visual() != xproto.Visualid(u32(raw, 8)) ||
56+ r.Class() != xproto.WindowClassInputOutput || r.BitGravity() != xproto.GravityBitForget ||
57+ r.WinGravity() != xproto.GravityNorthWest || r.BackingPlanes() != 0xffffffff || r.BackingPixel() != 0 ||
58+ !r.SaveUnder() || !r.MapIsInstalled() || r.MapState() != xproto.MapStateUnmapped || r.OverrideRedirect() ||
59+ r.Colormap() != xproto.Colormap(u32(raw, 28)) || r.AllEventMasks() != 0 || r.YourEventMask() != 0 ||
60+ r.DoNotPropagateMask() != 0 {
61+ t.Fatal("decoded attributes")
62+ }
63+ })
64+ t.Run("xproto/InternAtom", func(t *testing.T) {
65+ raw := loadReply(t, "xproto/InternAtom")
66+ r, ok := xproto.ParseInternAtomReply(raw)
67+ if !ok || r.Atom() == xproto.AtomNone || r.Atom() != xproto.Atom(u32(raw, 8)) {
68+ t.Fatal("atom")
69+ }
70+ })
71+ t.Run("xproto/GetProperty", func(t *testing.T) {
72+ raw := loadReply(t, "xproto/GetProperty")
73+ r, ok := xproto.ParseGetPropertyReply(raw)
74+ if !ok || r.Format() != 8 || r.Type() != xproto.AtomString || r.BytesAfter() != 0 || r.ValueLen() != 3 ||
75+ string(r.Value()) != "abc" || cap(r.Value()) != 3 {
76+ t.Fatalf("value %q", r.Value())
77+ }
78+ })
79+ t.Run("xproto/GetPropertyEmpty", func(t *testing.T) {
80+ raw := loadReply(t, "xproto/GetPropertyEmpty")
81+ r, ok := xproto.ParseGetPropertyReply(raw)
82+ if !ok || r.Format() != 0 || r.Type() != xproto.AtomNone || r.ValueLen() != 0 || len(r.Value()) != 0 {
83+ t.Fatal("empty property")
84+ }
85+ })
86+ t.Run("xproto/QueryExtension", func(t *testing.T) {
87+ raw := loadReply(t, "xproto/QueryExtension")
88+ r, ok := xproto.ParseQueryExtensionReply(raw)
89+ if !ok || !r.Present() || r.MajorOpcode() < 128 || r.FirstEvent() != raw[10] || r.FirstError() != raw[11] {
90+ t.Fatal("XFIXES query")
91+ }
92+ })
93+ t.Run("xproto/ListExtensions", func(t *testing.T) {
94+ raw := loadReply(t, "xproto/ListExtensions")
95+ r, ok := xproto.ParseListExtensionsReply(raw)
96+ if !ok {
97+ t.Fatal("parse")
98+ }
99+ it := r.Names()
100+ var names []string
101+ total := 32
102+ for it.Next() {
103+ v := it.Value()
104+ if int(v.NameLen()) != len(v.Name()) || v.Size() != 1+len(v.Name()) {
105+ t.Fatal("STR view")
106+ }
107+ names = append(names, string(v.Name()))
108+ total += v.Size()
109+ }
110+ if it.Err() || len(names) != int(r.NamesLen()) || total > len(raw) || len(raw)-total > 3 {
111+ t.Fatalf("iterated %d of %d, %d/%d bytes", len(names), r.NamesLen(), total, len(raw))
112+ }
113+ found := map[string]bool{}
114+ for _, n := range names {
115+ found[n] = true
116+ }
117+ for _, want := range []string{"XFIXES", "RENDER", "BIG-REQUESTS", "Composite", "X-Resource"} {
118+ if !found[want] {
119+ t.Fatalf("missing %s in %q", want, names)
120+ }
121+ }
122+ })
123+ t.Run("xfixes/QueryVersion", func(t *testing.T) {
124+ r, ok := xfixes.ParseQueryVersionReply(loadReply(t, "xfixes/QueryVersion"))
125+ if !ok || r.MajorVersion() != 6 || r.MinorVersion() != 0 {
126+ t.Fatal("version")
127+ }
128+ })
129+ t.Run("res/QueryClientIds", func(t *testing.T) {
130+ r, ok := res.ParseQueryClientIdsReply(loadReply(t, "res/QueryClientIds"))
131+ if !ok || r.NumIds() != 2 {
132+ t.Fatal("parse")
133+ }
134+ // Spec client 0 asks for every client's XID: the server client and ours.
135+ it := r.Ids()
136+ var clients []uint32
137+ for it.Next() {
138+ v := it.Value()
139+ if v.Spec().Mask != res.ClientIdMaskClientXID || v.Length() != 0 || v.Value().Len() != 0 || v.Size() != 12 {
140+ t.Fatal("ClientIdValue view")
141+ }
142+ clients = append(clients, v.Spec().Client)
143+ }
144+ if it.Err() || len(clients) != 2 || clients[0] != 0 || clients[1] == 0 {
145+ t.Fatalf("clients %x", clients)
146+ }
147+ })
148+ t.Run("render/QueryPictFormats", func(t *testing.T) {
149+ raw := loadReply(t, "render/QueryPictFormats")
150+ r, ok := render.ParseQueryPictFormatsReply(raw)
151+ if !ok || r.NumScreens() != 1 || r.Formats().Len() != int(r.NumFormats()) || r.Subpixels().Len() != int(r.NumSubpixel()) {
152+ t.Fatal("counts")
153+ }
154+ formats := map[render.Pictformat]bool{}
155+ for i := range r.Formats().Len() {
156+ f := r.Formats().At(i)
157+ formats[f.Id] = true
158+ }
159+ screens := r.Screens()
160+ visuals := 0
161+ for screens.Next() {
162+ depths := screens.Value().Depths()
163+ for depths.Next() {
164+ vs := depths.Value().Visuals()
165+ for i := range vs.Len() {
166+ if !formats[vs.At(i).Format] {
167+ t.Fatal("visual references an unknown format")
168+ }
169+ visuals++
170+ }
171+ }
172+ if depths.Err() {
173+ t.Fatal("depth iterator")
174+ }
175+ }
176+ if screens.Err() || visuals == 0 {
177+ t.Fatal("screen iterator")
178+ }
179+ for i := range r.Subpixels().Len() {
180+ if r.Subpixels().At(i) != render.SubPixelUnknown {
181+ t.Fatal("Xvfb subpixel order")
182+ }
183+ }
184+ })
185+}
186+
187+func TestReplyParseRejects(t *testing.T) {
188+ raw := loadReply(t, "xproto/QueryTree")
189+ if _, ok := xproto.ParseQueryTreeReply(raw[:31]); ok {
190+ t.Fatal("short fixed prefix accepted")
191+ }
192+ if _, ok := xproto.ParseQueryTreeReply(raw[:len(raw)-1]); ok {
193+ t.Fatal("truncated list accepted")
194+ }
195+ raw = loadReply(t, "xproto/GetWindowAttributes")
196+ if _, ok := xproto.ParseGetWindowAttributesReply(raw[:43]); ok {
197+ t.Fatal("44-byte reply prefix not enforced")
198+ }
199+ raw = bytes.Clone(loadReply(t, "xproto/ListExtensions"))
200+ raw[1] = 255 // names_len: far more STRs than the reply holds
201+ if _, ok := xproto.ParseListExtensionsReply(raw); ok {
202+ t.Fatal("STR count beyond the reply accepted")
203+ }
204+ prop := bytes.Clone(loadReply(t, "xproto/GetProperty"))
205+ prop[1] = 32 // 3 items of 4 bytes overrun the 36-byte reply
206+ if _, ok := xproto.ParseGetPropertyReply(prop); ok {
207+ t.Fatal("format*value_len overrun accepted")
208+ }
209+}
210+
211+func TestReplyAllocs(t *testing.T) {
212+ prop := loadReply(t, "xproto/GetProperty")
213+ tree := loadReply(t, "xproto/QueryTree")
214+ exts := loadReply(t, "xproto/ListExtensions")
215+ formats := loadReply(t, "render/QueryPictFormats")
216+ ids := loadReply(t, "res/QueryClientIds")
217+ var sink uint64
218+ n := testing.AllocsPerRun(1000, func() {
219+ p, _ := xproto.ParseGetPropertyReply(prop)
220+ v := p.Value()
221+ sink += uint64(len(v)) + uint64(p.Type()) + uint64(p.Format())
222+ q, _ := xproto.ParseQueryTreeReply(tree)
223+ c := q.Children()
224+ for i := range c.Len() {
225+ sink += uint64(c.At(i))
226+ }
227+ sink += uint64(q.Root()) + uint64(q.Parent())
228+ l, _ := xproto.ParseListExtensionsReply(exts)
229+ it := l.Names()
230+ for it.Next() {
231+ sink += uint64(len(it.Value().Name()))
232+ }
233+ f, _ := render.ParseQueryPictFormatsReply(formats)
234+ fl := f.Formats()
235+ for i := range fl.Len() {
236+ sink += uint64(fl.At(i).Id)
237+ }
238+ s := f.Screens()
239+ for s.Next() {
240+ d := s.Value().Depths()
241+ for d.Next() {
242+ vs := d.Value().Visuals()
243+ for i := range vs.Len() {
244+ sink += uint64(vs.At(i).Visual)
245+ }
246+ }
247+ }
248+ sp := f.Subpixels()
249+ for i := range sp.Len() {
250+ sink += uint64(sp.At(i))
251+ }
252+ r, _ := res.ParseQueryClientIdsReply(ids)
253+ ri := r.Ids()
254+ for ri.Next() {
255+ sink += uint64(ri.Value().Value().Len())
256+ }
257+ })
258+ if n != 0 {
259+ t.Fatalf("reply parse/getters/iteration allocate %v times", n)
260+ }
261+ _ = sink
262+}
263+
264+func BenchmarkGetPropertyReply(b *testing.B) {
265+ raw := loadReply(b, "xproto/GetProperty")
266+ var sink int
267+ b.ReportAllocs()
268+ for b.Loop() {
269+ r, ok := xproto.ParseGetPropertyReply(raw)
270+ if !ok {
271+ b.Fatal("parse")
272+ }
273+ sink += len(r.Value()) + int(r.Type())
274+ }
275+ _ = sink
276+}
277+
278+func BenchmarkQueryTreeReply(b *testing.B) {
279+ raw := loadReply(b, "xproto/QueryTree")
280+ var sink xproto.Window
281+ b.ReportAllocs()
282+ for b.Loop() {
283+ r, _ := xproto.ParseQueryTreeReply(raw)
284+ c := r.Children()
285+ for i := range c.Len() {
286+ sink ^= c.At(i)
287+ }
288+ }
289+ _ = sink
290+}
291+
292+func BenchmarkListExtensionsReply(b *testing.B) {
293+ raw := loadReply(b, "xproto/ListExtensions")
294+ var sink int
295+ b.ReportAllocs()
296+ for b.Loop() {
297+ r, _ := xproto.ParseListExtensionsReply(raw)
298+ it := r.Names()
299+ for it.Next() {
300+ sink += len(it.Value().Name())
301+ }
302+ }
303+ _ = sink
304+}
A res/replies_fuzz_test.go +146 -0
@@ -0,0 +1,146 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package res
3+
4+import "testing"
5+import "bnema.dev/xturbo/internal/xtest"
6+
7+func FuzzParseQueryVersionReply(f *testing.F) {
8+ f.Add(make([]byte, 32))
9+ f.Fuzz(func(t *testing.T, raw []byte) {
10+ r, ok := ParseQueryVersionReply(raw)
11+ if !ok {
12+ if len(raw) >= 32 {
13+ t.Fatal("rejected a complete fixed-size reply")
14+ }
15+ return
16+ }
17+ if len(r.Raw()) != len(raw) {
18+ t.Fatal("Raw must return the parsed bytes")
19+ }
20+ _ = r.ServerMajor()
21+ _ = r.ServerMinor()
22+ })
23+}
24+
25+func FuzzParseQueryClientsReply(f *testing.F) {
26+ f.Add(make([]byte, 32))
27+ f.Fuzz(func(t *testing.T, raw []byte) {
28+ r, ok := ParseQueryClientsReply(raw)
29+ if !ok {
30+ return
31+ }
32+ if len(r.Raw()) != len(raw) {
33+ t.Fatal("Raw must return the parsed bytes")
34+ }
35+ _ = r.NumClients()
36+ {
37+ l0 := r.Clients()
38+ for i := 0; i < l0.Len(); i++ {
39+ _ = l0.At(i)
40+ }
41+ }
42+ })
43+}
44+
45+func FuzzParseQueryClientResourcesReply(f *testing.F) {
46+ f.Add(make([]byte, 32))
47+ f.Fuzz(func(t *testing.T, raw []byte) {
48+ r, ok := ParseQueryClientResourcesReply(raw)
49+ if !ok {
50+ return
51+ }
52+ if len(r.Raw()) != len(raw) {
53+ t.Fatal("Raw must return the parsed bytes")
54+ }
55+ _ = r.NumTypes()
56+ {
57+ l0 := r.Types()
58+ for i := 0; i < l0.Len(); i++ {
59+ _ = l0.At(i)
60+ }
61+ }
62+ })
63+}
64+
65+func FuzzParseQueryClientPixmapBytesReply(f *testing.F) {
66+ f.Add(make([]byte, 32))
67+ f.Fuzz(func(t *testing.T, raw []byte) {
68+ r, ok := ParseQueryClientPixmapBytesReply(raw)
69+ if !ok {
70+ if len(raw) >= 32 {
71+ t.Fatal("rejected a complete fixed-size reply")
72+ }
73+ return
74+ }
75+ if len(r.Raw()) != len(raw) {
76+ t.Fatal("Raw must return the parsed bytes")
77+ }
78+ _ = r.Bytes()
79+ _ = r.BytesOverflow()
80+ })
81+}
82+
83+func FuzzParseQueryClientIdsReply(f *testing.F) {
84+ f.Add(make([]byte, 32))
85+ if raw, err := xtest.LoadHex("../testdata/golden/res/QueryClientIds.reply.hex"); err != nil {
86+ f.Fatal(err)
87+ } else {
88+ f.Add(raw)
89+ }
90+ f.Fuzz(func(t *testing.T, raw []byte) {
91+ r, ok := ParseQueryClientIdsReply(raw)
92+ if !ok {
93+ return
94+ }
95+ if len(r.Raw()) != len(raw) {
96+ t.Fatal("Raw must return the parsed bytes")
97+ }
98+ _ = r.NumIds()
99+ {
100+ it0 := r.Ids()
101+ for it0.Next() {
102+ _ = it0.Value().Spec()
103+ _ = it0.Value().Length()
104+ {
105+ l1 := it0.Value().Value()
106+ for i := 0; i < l1.Len(); i++ {
107+ _ = l1.At(i)
108+ }
109+ }
110+ }
111+ if it0.Err() {
112+ t.Fatal("iterator error after successful Parse")
113+ }
114+ }
115+ })
116+}
117+
118+func FuzzParseQueryResourceBytesReply(f *testing.F) {
119+ f.Add(make([]byte, 32))
120+ f.Fuzz(func(t *testing.T, raw []byte) {
121+ r, ok := ParseQueryResourceBytesReply(raw)
122+ if !ok {
123+ return
124+ }
125+ if len(r.Raw()) != len(raw) {
126+ t.Fatal("Raw must return the parsed bytes")
127+ }
128+ _ = r.NumSizes()
129+ {
130+ it0 := r.Sizes()
131+ for it0.Next() {
132+ _ = it0.Value().Size_()
133+ _ = it0.Value().NumCrossReferences()
134+ {
135+ l1 := it0.Value().CrossReferences()
136+ for i := 0; i < l1.Len(); i++ {
137+ _ = l1.At(i)
138+ }
139+ }
140+ }
141+ if it0.Err() {
142+ t.Fatal("iterator error after successful Parse")
143+ }
144+ }
145+ })
146+}
A res/replies_generated.go +348 -0
@@ -0,0 +1,348 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package res
3+
4+import "encoding/binary"
5+
6+// QueryVersionReply is a zero-copy view over a QueryVersion reply; offsets count from reply byte 0.
7+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
8+type QueryVersionReply struct{ raw []byte }
9+
10+// ParseQueryVersionReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
11+func ParseQueryVersionReply(raw []byte) (QueryVersionReply, bool) {
12+ if len(raw) < 32 {
13+ return QueryVersionReply{}, false
14+ }
15+ r := QueryVersionReply{raw: raw}
16+ return r, true
17+}
18+func (r QueryVersionReply) Raw() []byte { return r.raw }
19+func (r QueryVersionReply) ServerMajor() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[8:])) }
20+func (r QueryVersionReply) ServerMinor() uint16 {
21+ return uint16(binary.LittleEndian.Uint16(r.raw[10:]))
22+}
23+
24+// QueryClientsReply is a zero-copy view over a QueryClients reply; offsets count from reply byte 0.
25+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
26+type QueryClientsReply struct{ raw []byte }
27+
28+// ParseQueryClientsReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
29+func ParseQueryClientsReply(raw []byte) (QueryClientsReply, bool) {
30+ if len(raw) < 32 {
31+ return QueryClientsReply{}, false
32+ }
33+ r := QueryClientsReply{raw: raw}
34+ off := 32
35+ {
36+ n := int(r.NumClients())
37+ if n < 0 || n > len(r.raw) {
38+ return QueryClientsReply{}, false
39+ }
40+ off += n * 8
41+ }
42+ if off > len(r.raw) {
43+ return QueryClientsReply{}, false
44+ }
45+ if off > len(r.raw) {
46+ return QueryClientsReply{}, false
47+ }
48+ return r, true
49+}
50+func (r QueryClientsReply) Raw() []byte { return r.raw }
51+func (r QueryClientsReply) NumClients() uint32 { return uint32(binary.LittleEndian.Uint32(r.raw[8:])) }
52+func (r QueryClientsReply) Clients() ClientList {
53+ off := 32
54+ end := off + (int(r.NumClients()))*8
55+ return ClientList{b: r.raw[off:end:end]}
56+}
57+
58+// QueryClientResourcesReply is a zero-copy view over a QueryClientResources reply; offsets count from reply byte 0.
59+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
60+type QueryClientResourcesReply struct{ raw []byte }
61+
62+// ParseQueryClientResourcesReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
63+func ParseQueryClientResourcesReply(raw []byte) (QueryClientResourcesReply, bool) {
64+ if len(raw) < 32 {
65+ return QueryClientResourcesReply{}, false
66+ }
67+ r := QueryClientResourcesReply{raw: raw}
68+ off := 32
69+ {
70+ n := int(r.NumTypes())
71+ if n < 0 || n > len(r.raw) {
72+ return QueryClientResourcesReply{}, false
73+ }
74+ off += n * 8
75+ }
76+ if off > len(r.raw) {
77+ return QueryClientResourcesReply{}, false
78+ }
79+ if off > len(r.raw) {
80+ return QueryClientResourcesReply{}, false
81+ }
82+ return r, true
83+}
84+func (r QueryClientResourcesReply) Raw() []byte { return r.raw }
85+func (r QueryClientResourcesReply) NumTypes() uint32 {
86+ return uint32(binary.LittleEndian.Uint32(r.raw[8:]))
87+}
88+func (r QueryClientResourcesReply) Types() TypeList {
89+ off := 32
90+ end := off + (int(r.NumTypes()))*8
91+ return TypeList{b: r.raw[off:end:end]}
92+}
93+
94+// QueryClientPixmapBytesReply is a zero-copy view over a QueryClientPixmapBytes reply; offsets count from reply byte 0.
95+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
96+type QueryClientPixmapBytesReply struct{ raw []byte }
97+
98+// ParseQueryClientPixmapBytesReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
99+func ParseQueryClientPixmapBytesReply(raw []byte) (QueryClientPixmapBytesReply, bool) {
100+ if len(raw) < 32 {
101+ return QueryClientPixmapBytesReply{}, false
102+ }
103+ r := QueryClientPixmapBytesReply{raw: raw}
104+ return r, true
105+}
106+func (r QueryClientPixmapBytesReply) Raw() []byte { return r.raw }
107+func (r QueryClientPixmapBytesReply) Bytes() uint32 {
108+ return uint32(binary.LittleEndian.Uint32(r.raw[8:]))
109+}
110+func (r QueryClientPixmapBytesReply) BytesOverflow() uint32 {
111+ return uint32(binary.LittleEndian.Uint32(r.raw[12:]))
112+}
113+
114+// QueryClientIdsReply is a zero-copy view over a QueryClientIds reply; offsets count from reply byte 0.
115+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
116+type QueryClientIdsReply struct{ raw []byte }
117+
118+// ParseQueryClientIdsReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
119+func ParseQueryClientIdsReply(raw []byte) (QueryClientIdsReply, bool) {
120+ if len(raw) < 32 {
121+ return QueryClientIdsReply{}, false
122+ }
123+ r := QueryClientIdsReply{raw: raw}
124+ off := 32
125+ {
126+ n := int(r.NumIds())
127+ if off > len(r.raw) || n < 0 || n > len(r.raw) {
128+ return QueryClientIdsReply{}, false
129+ }
130+ it := NewClientIdValueIter(r.raw[off:], n)
131+ for it.Next() {
132+ off += it.Value().Size()
133+ }
134+ if it.Err() {
135+ return QueryClientIdsReply{}, false
136+ }
137+ }
138+ if off > len(r.raw) {
139+ return QueryClientIdsReply{}, false
140+ }
141+ return r, true
142+}
143+func (r QueryClientIdsReply) Raw() []byte { return r.raw }
144+func (r QueryClientIdsReply) NumIds() uint32 { return uint32(binary.LittleEndian.Uint32(r.raw[8:])) }
145+func (r QueryClientIdsReply) Ids() ClientIdValueIter {
146+ off := 32
147+ return NewClientIdValueIter(r.raw[off:], int(r.NumIds()))
148+}
149+
150+// QueryResourceBytesReply is a zero-copy view over a QueryResourceBytes reply; offsets count from reply byte 0.
151+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
152+type QueryResourceBytesReply struct{ raw []byte }
153+
154+// ParseQueryResourceBytesReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
155+func ParseQueryResourceBytesReply(raw []byte) (QueryResourceBytesReply, bool) {
156+ if len(raw) < 32 {
157+ return QueryResourceBytesReply{}, false
158+ }
159+ r := QueryResourceBytesReply{raw: raw}
160+ off := 32
161+ {
162+ n := int(r.NumSizes())
163+ if off > len(r.raw) || n < 0 || n > len(r.raw) {
164+ return QueryResourceBytesReply{}, false
165+ }
166+ it := NewResourceSizeValueIter(r.raw[off:], n)
167+ for it.Next() {
168+ off += it.Value().Size()
169+ }
170+ if it.Err() {
171+ return QueryResourceBytesReply{}, false
172+ }
173+ }
174+ if off > len(r.raw) {
175+ return QueryResourceBytesReply{}, false
176+ }
177+ return r, true
178+}
179+func (r QueryResourceBytesReply) Raw() []byte { return r.raw }
180+func (r QueryResourceBytesReply) NumSizes() uint32 {
181+ return uint32(binary.LittleEndian.Uint32(r.raw[8:]))
182+}
183+func (r QueryResourceBytesReply) Sizes() ResourceSizeValueIter {
184+ off := 32
185+ return NewResourceSizeValueIter(r.raw[off:], int(r.NumSizes()))
186+}
187+
188+// ClientIdValueView is a zero-copy view over one wire-encoded ClientIdValue, yielded by ClientIdValueIter.
189+// It shares the lifetime of the bytes it was taken from (for replies: until the Handler callback returns). Copy what you keep.
190+type ClientIdValueView struct{ raw []byte }
191+
192+func (v ClientIdValueView) Raw() []byte { return v.raw }
193+
194+// Size is the element's wire size, including trailing alignment.
195+func (v ClientIdValueView) Size() int { return len(v.raw) }
196+func sizeClientIdValue(p []byte) int {
197+ if len(p) < 12 {
198+ return -1
199+ }
200+ v := ClientIdValueView{raw: p}
201+ _ = v
202+ off := 12
203+ {
204+ n := (int(v.Length()) / 4)
205+ if n < 0 || n > len(v.raw) {
206+ return -1
207+ }
208+ off += n * 4
209+ }
210+ if off > len(v.raw) {
211+ return -1
212+ }
213+ if off > len(v.raw) {
214+ return -1
215+ }
216+ return off
217+}
218+func (v ClientIdValueView) Spec() ClientIdSpec { return GetClientIdSpec(v.raw[0:]) }
219+func (v ClientIdValueView) Length() uint32 { return uint32(binary.LittleEndian.Uint32(v.raw[8:])) }
220+func (v ClientIdValueView) Value() Uint32List {
221+ off := 12
222+ end := off + (int(v.Length())/4)*4
223+ return Uint32List{b: v.raw[off:end:end]}
224+}
225+
226+// ClientIdValueIter walks n consecutive ClientIdValue elements; Err reports a malformed length.
227+// It shares the lifetime of the bytes it walks.
228+type ClientIdValueIter struct {
229+ b []byte
230+ n int
231+ v ClientIdValueView
232+ err bool
233+}
234+
235+// NewClientIdValueIter iterates n elements encoded at the start of b.
236+func NewClientIdValueIter(b []byte, n int) ClientIdValueIter { return ClientIdValueIter{b: b, n: n} }
237+func (it *ClientIdValueIter) Next() bool {
238+ if it.n <= 0 || it.err {
239+ return false
240+ }
241+ s := sizeClientIdValue(it.b)
242+ if s < 0 {
243+ it.err = true
244+ it.n = 0
245+ return false
246+ }
247+ it.v = ClientIdValueView{raw: it.b[:s:s]}
248+ it.b = it.b[s:]
249+ it.n--
250+ return true
251+}
252+func (it *ClientIdValueIter) Value() ClientIdValueView { return it.v }
253+func (it *ClientIdValueIter) Err() bool { return it.err }
254+
255+// ResourceSizeValueView is a zero-copy view over one wire-encoded ResourceSizeValue, yielded by ResourceSizeValueIter.
256+// It shares the lifetime of the bytes it was taken from (for replies: until the Handler callback returns). Copy what you keep.
257+type ResourceSizeValueView struct{ raw []byte }
258+
259+func (v ResourceSizeValueView) Raw() []byte { return v.raw }
260+
261+// Size is the element's wire size, including trailing alignment.
262+func (v ResourceSizeValueView) Size() int { return len(v.raw) }
263+func sizeResourceSizeValue(p []byte) int {
264+ if len(p) < 24 {
265+ return -1
266+ }
267+ v := ResourceSizeValueView{raw: p}
268+ _ = v
269+ off := 24
270+ {
271+ n := int(v.NumCrossReferences())
272+ if n < 0 || n > len(v.raw) {
273+ return -1
274+ }
275+ off += n * 20
276+ }
277+ if off > len(v.raw) {
278+ return -1
279+ }
280+ if off > len(v.raw) {
281+ return -1
282+ }
283+ return off
284+}
285+func (v ResourceSizeValueView) Size_() ResourceSizeSpec { return GetResourceSizeSpec(v.raw[0:]) }
286+func (v ResourceSizeValueView) NumCrossReferences() uint32 {
287+ return uint32(binary.LittleEndian.Uint32(v.raw[20:]))
288+}
289+func (v ResourceSizeValueView) CrossReferences() ResourceSizeSpecList {
290+ off := 24
291+ end := off + (int(v.NumCrossReferences()))*20
292+ return ResourceSizeSpecList{b: v.raw[off:end:end]}
293+}
294+
295+// ResourceSizeValueIter walks n consecutive ResourceSizeValue elements; Err reports a malformed length.
296+// It shares the lifetime of the bytes it walks.
297+type ResourceSizeValueIter struct {
298+ b []byte
299+ n int
300+ v ResourceSizeValueView
301+ err bool
302+}
303+
304+// NewResourceSizeValueIter iterates n elements encoded at the start of b.
305+func NewResourceSizeValueIter(b []byte, n int) ResourceSizeValueIter {
306+ return ResourceSizeValueIter{b: b, n: n}
307+}
308+func (it *ResourceSizeValueIter) Next() bool {
309+ if it.n <= 0 || it.err {
310+ return false
311+ }
312+ s := sizeResourceSizeValue(it.b)
313+ if s < 0 {
314+ it.err = true
315+ it.n = 0
316+ return false
317+ }
318+ it.v = ResourceSizeValueView{raw: it.b[:s:s]}
319+ it.b = it.b[s:]
320+ it.n--
321+ return true
322+}
323+func (it *ResourceSizeValueIter) Value() ResourceSizeValueView { return it.v }
324+func (it *ResourceSizeValueIter) Err() bool { return it.err }
325+
326+// ClientList is a borrowed view over a wire list of Client. It shares the lifetime of the bytes it was taken from; copy what you keep.
327+type ClientList struct{ b []byte }
328+
329+func (l ClientList) Len() int { return len(l.b) / 8 }
330+func (l ClientList) At(i int) Client { return GetClient(l.b[i*8:]) }
331+
332+// ResourceSizeSpecList is a borrowed view over a wire list of ResourceSizeSpec. It shares the lifetime of the bytes it was taken from; copy what you keep.
333+type ResourceSizeSpecList struct{ b []byte }
334+
335+func (l ResourceSizeSpecList) Len() int { return len(l.b) / 20 }
336+func (l ResourceSizeSpecList) At(i int) ResourceSizeSpec { return GetResourceSizeSpec(l.b[i*20:]) }
337+
338+// TypeList is a borrowed view over a wire list of Type. It shares the lifetime of the bytes it was taken from; copy what you keep.
339+type TypeList struct{ b []byte }
340+
341+func (l TypeList) Len() int { return len(l.b) / 8 }
342+func (l TypeList) At(i int) Type { return GetType(l.b[i*8:]) }
343+
344+// Uint32List is a borrowed view over a wire list of uint32. It shares the lifetime of the bytes it was taken from; copy what you keep.
345+type Uint32List struct{ b []byte }
346+
347+func (l Uint32List) Len() int { return len(l.b) / 4 }
348+func (l Uint32List) At(i int) uint32 { return uint32(binary.LittleEndian.Uint32(l.b[i*4:])) }
A shape/replies_fuzz_test.go +86 -0
@@ -0,0 +1,86 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package shape
3+
4+import "testing"
5+
6+func FuzzParseQueryVersionReply(f *testing.F) {
7+ f.Add(make([]byte, 32))
8+ f.Fuzz(func(t *testing.T, raw []byte) {
9+ r, ok := ParseQueryVersionReply(raw)
10+ if !ok {
11+ if len(raw) >= 32 {
12+ t.Fatal("rejected a complete fixed-size reply")
13+ }
14+ return
15+ }
16+ if len(r.Raw()) != len(raw) {
17+ t.Fatal("Raw must return the parsed bytes")
18+ }
19+ _ = r.MajorVersion()
20+ _ = r.MinorVersion()
21+ })
22+}
23+
24+func FuzzParseQueryExtentsReply(f *testing.F) {
25+ f.Add(make([]byte, 32))
26+ f.Fuzz(func(t *testing.T, raw []byte) {
27+ r, ok := ParseQueryExtentsReply(raw)
28+ if !ok {
29+ if len(raw) >= 32 {
30+ t.Fatal("rejected a complete fixed-size reply")
31+ }
32+ return
33+ }
34+ if len(r.Raw()) != len(raw) {
35+ t.Fatal("Raw must return the parsed bytes")
36+ }
37+ _ = r.BoundingShaped()
38+ _ = r.ClipShaped()
39+ _ = r.BoundingShapeExtentsX()
40+ _ = r.BoundingShapeExtentsY()
41+ _ = r.BoundingShapeExtentsWidth()
42+ _ = r.BoundingShapeExtentsHeight()
43+ _ = r.ClipShapeExtentsX()
44+ _ = r.ClipShapeExtentsY()
45+ _ = r.ClipShapeExtentsWidth()
46+ _ = r.ClipShapeExtentsHeight()
47+ })
48+}
49+
50+func FuzzParseInputSelectedReply(f *testing.F) {
51+ f.Add(make([]byte, 32))
52+ f.Fuzz(func(t *testing.T, raw []byte) {
53+ r, ok := ParseInputSelectedReply(raw)
54+ if !ok {
55+ if len(raw) >= 32 {
56+ t.Fatal("rejected a complete fixed-size reply")
57+ }
58+ return
59+ }
60+ if len(r.Raw()) != len(raw) {
61+ t.Fatal("Raw must return the parsed bytes")
62+ }
63+ _ = r.Enabled()
64+ })
65+}
66+
67+func FuzzParseGetRectanglesReply(f *testing.F) {
68+ f.Add(make([]byte, 32))
69+ f.Fuzz(func(t *testing.T, raw []byte) {
70+ r, ok := ParseGetRectanglesReply(raw)
71+ if !ok {
72+ return
73+ }
74+ if len(r.Raw()) != len(raw) {
75+ t.Fatal("Raw must return the parsed bytes")
76+ }
77+ _ = r.Ordering()
78+ _ = r.RectanglesLen()
79+ {
80+ l0 := r.Rectangles()
81+ for i := 0; i < l0.Len(); i++ {
82+ _ = l0.At(i)
83+ }
84+ }
85+ })
86+}
A shape/replies_generated.go +123 -0
@@ -0,0 +1,123 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package shape
3+
4+import "bnema.dev/xturbo/xproto"
5+import "encoding/binary"
6+
7+// QueryVersionReply is a zero-copy view over a QueryVersion reply; offsets count from reply byte 0.
8+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
9+type QueryVersionReply struct{ raw []byte }
10+
11+// ParseQueryVersionReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
12+func ParseQueryVersionReply(raw []byte) (QueryVersionReply, bool) {
13+ if len(raw) < 32 {
14+ return QueryVersionReply{}, false
15+ }
16+ r := QueryVersionReply{raw: raw}
17+ return r, true
18+}
19+func (r QueryVersionReply) Raw() []byte { return r.raw }
20+func (r QueryVersionReply) MajorVersion() uint16 {
21+ return uint16(binary.LittleEndian.Uint16(r.raw[8:]))
22+}
23+func (r QueryVersionReply) MinorVersion() uint16 {
24+ return uint16(binary.LittleEndian.Uint16(r.raw[10:]))
25+}
26+
27+// QueryExtentsReply is a zero-copy view over a QueryExtents reply; offsets count from reply byte 0.
28+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
29+type QueryExtentsReply struct{ raw []byte }
30+
31+// ParseQueryExtentsReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
32+func ParseQueryExtentsReply(raw []byte) (QueryExtentsReply, bool) {
33+ if len(raw) < 32 {
34+ return QueryExtentsReply{}, false
35+ }
36+ r := QueryExtentsReply{raw: raw}
37+ return r, true
38+}
39+func (r QueryExtentsReply) Raw() []byte { return r.raw }
40+func (r QueryExtentsReply) BoundingShaped() bool { return (r.raw[8:][0] != 0) }
41+func (r QueryExtentsReply) ClipShaped() bool { return (r.raw[9:][0] != 0) }
42+func (r QueryExtentsReply) BoundingShapeExtentsX() int16 {
43+ return int16(binary.LittleEndian.Uint16(r.raw[12:]))
44+}
45+func (r QueryExtentsReply) BoundingShapeExtentsY() int16 {
46+ return int16(binary.LittleEndian.Uint16(r.raw[14:]))
47+}
48+func (r QueryExtentsReply) BoundingShapeExtentsWidth() uint16 {
49+ return uint16(binary.LittleEndian.Uint16(r.raw[16:]))
50+}
51+func (r QueryExtentsReply) BoundingShapeExtentsHeight() uint16 {
52+ return uint16(binary.LittleEndian.Uint16(r.raw[18:]))
53+}
54+func (r QueryExtentsReply) ClipShapeExtentsX() int16 {
55+ return int16(binary.LittleEndian.Uint16(r.raw[20:]))
56+}
57+func (r QueryExtentsReply) ClipShapeExtentsY() int16 {
58+ return int16(binary.LittleEndian.Uint16(r.raw[22:]))
59+}
60+func (r QueryExtentsReply) ClipShapeExtentsWidth() uint16 {
61+ return uint16(binary.LittleEndian.Uint16(r.raw[24:]))
62+}
63+func (r QueryExtentsReply) ClipShapeExtentsHeight() uint16 {
64+ return uint16(binary.LittleEndian.Uint16(r.raw[26:]))
65+}
66+
67+// InputSelectedReply is a zero-copy view over a InputSelected reply; offsets count from reply byte 0.
68+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
69+type InputSelectedReply struct{ raw []byte }
70+
71+// ParseInputSelectedReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
72+func ParseInputSelectedReply(raw []byte) (InputSelectedReply, bool) {
73+ if len(raw) < 32 {
74+ return InputSelectedReply{}, false
75+ }
76+ r := InputSelectedReply{raw: raw}
77+ return r, true
78+}
79+func (r InputSelectedReply) Raw() []byte { return r.raw }
80+func (r InputSelectedReply) Enabled() bool { return (r.raw[1:][0] != 0) }
81+
82+// GetRectanglesReply is a zero-copy view over a GetRectangles reply; offsets count from reply byte 0.
83+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
84+type GetRectanglesReply struct{ raw []byte }
85+
86+// ParseGetRectanglesReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
87+func ParseGetRectanglesReply(raw []byte) (GetRectanglesReply, bool) {
88+ if len(raw) < 32 {
89+ return GetRectanglesReply{}, false
90+ }
91+ r := GetRectanglesReply{raw: raw}
92+ off := 32
93+ {
94+ n := int(r.RectanglesLen())
95+ if n < 0 || n > len(r.raw) {
96+ return GetRectanglesReply{}, false
97+ }
98+ off += n * 8
99+ }
100+ if off > len(r.raw) {
101+ return GetRectanglesReply{}, false
102+ }
103+ if off > len(r.raw) {
104+ return GetRectanglesReply{}, false
105+ }
106+ return r, true
107+}
108+func (r GetRectanglesReply) Raw() []byte { return r.raw }
109+func (r GetRectanglesReply) Ordering() xproto.ClipOrdering { return xproto.ClipOrdering(r.raw[1:][0]) }
110+func (r GetRectanglesReply) RectanglesLen() uint32 {
111+ return uint32(binary.LittleEndian.Uint32(r.raw[8:]))
112+}
113+func (r GetRectanglesReply) Rectangles() RectangleList {
114+ off := 32
115+ end := off + (int(r.RectanglesLen()))*8
116+ return RectangleList{b: r.raw[off:end:end]}
117+}
118+
119+// RectangleList is a borrowed view over a wire list of xproto.Rectangle. It shares the lifetime of the bytes it was taken from; copy what you keep.
120+type RectangleList struct{ b []byte }
121+
122+func (l RectangleList) Len() int { return len(l.b) / 8 }
123+func (l RectangleList) At(i int) xproto.Rectangle { return xproto.GetRectangle(l.b[i*8:]) }
A testdata/golden/render/QueryPictFormats.reply.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb reply via raw socketpair tee to an independent reference request
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+01001200cf0200001700000001000000060000001001000000000000000000002300000001010000000000000000000000000000000001000000000024000000010800000000000000000000000000000000ff000000000025000000012000001000ff000800ff000000ff001800ff000000000026000000012000001000ff000800ff000000ff00000000000000000027000000012000000800ff001000ff001800ff000000ff000000000028000000012000000800ff001000ff001800ff00000000000000000029000000011800001000ff000800ff000000ff0000000000000000002a000000011800000000ff000800ff001000ff0000000000000000002b0000000110000008000f0004000f0000000f0000000000000000002c0000000110000000000f0004000f0008000f0000000000000000002d000000011000000a001f0005001f0000001f0000000000000000002e0000000110000000001f0005001f000a001f0000000000000000002f000000011000000a001f0005001f0000001f000f00010000000000300000000110000000001f0005001f000a001f000f0001000000000031000000011000000b001f0005003f0000001f000000000000000000320000000110000000001f0005003f000b001f000000000000000000330000000110000008000f0004000f0000000f000c000f0000000000340000000110000000000f0004000f0008000f000c000f000000000035000000012000000000ff000800ff001000ff00000000000000000036000000012000001400ff030a00ff030000ff031e0003000000000037000000012000001400ff030a00ff030000ff03000000000000000038000000012000000000ff030a00ff031400ff031e0003000000000039000000012000000000ff030a00ff031400ff03000000000000000006000000230000001800000100000000210000002900000022000000290000009102000029000000920200002900000093020000290000009402000029000000950200002900000096020000290000009702000029000000980200002900000099020000290000009a020000290000009b020000290000009c020000290000009d020000290000009e020000290000009f02000029000000a002000029000000a102000029000000a202000029000000a302000029000000a402000029000000a502000029000000a602000029000000a702000029000000a802000029000000a902000029000000aa02000029000000ab02000029000000ac02000029000000ad02000029000000ae02000029000000af02000029000000b002000029000000b102000029000000b202000029000000b302000029000000b402000029000000b502000029000000b602000029000000b702000029000000b802000029000000b902000029000000ba02000029000000bb02000029000000bc02000029000000bd02000029000000be02000029000000bf02000029000000c002000029000000c102000029000000c202000029000000c302000029000000c402000029000000c502000029000000c602000029000000c702000029000000c802000029000000c902000029000000ca02000029000000cb02000029000000cc02000029000000cd02000029000000ce02000029000000cf02000029000000d002000029000000d102000029000000d202000029000000d302000029000000d402000029000000d502000029000000d602000029000000d702000029000000d802000029000000d902000029000000da02000029000000db02000029000000dc02000029000000dd02000029000000de02000029000000df02000029000000e002000029000000e102000029000000e202000029000000e302000029000000e402000029000000e502000029000000e602000029000000e702000029000000e802000029000000e902000029000000ea02000029000000eb02000029000000ec02000029000000ed02000029000000ee02000029000000ef02000029000000f002000029000000f102000029000000f202000029000000f302000029000000f402000029000000f502000029000000f602000029000000f702000029000000f802000029000000f902000029000000fa02000029000000fb02000029000000fc02000029000000fd02000029000000fe02000029000000ff0200002900000000030000290000000103000029000000020300002900000003030000290000000403000029000000050300002900000006030000290000000703000029000000080300002900000009030000290000000a030000290000000b030000290000000c030000290000000d030000290000000e030000290000000f0300002900000010030000290000001103000029000000120300002900000013030000290000001403000029000000150300002900000016030000290000001703000029000000180300002900000019030000290000001a030000290000001b030000290000001c030000290000001d030000290000001e030000290000001f0300002900000020030000290000002103000029000000220300002900000023030000290000002403000029000000250300002900000026030000290000002703000029000000280300002900000029030000290000002a030000290000002b030000290000002c030000290000002d030000290000002e030000290000002f0300002900000030030000290000003103000029000000320300002900000033030000290000003403000029000000350300002900000036030000290000003703000029000000380300002900000039030000290000003a030000290000003b030000290000003c030000290000003d030000290000003e030000290000003f0300002900000040030000290000004103000029000000420300002900000043030000290000004403000029000000450300002900000046030000290000004703000029000000480300002900000049030000290000004a030000290000004b030000290000004c030000290000004d030000290000004e030000290000004f0300002900000050030000290000005103000029000000520300002900000053030000290000005403000029000000550300002900000056030000290000005703000029000000580300002900000059030000290000005a030000290000005b030000290000005c030000290000005d030000290000005e030000290000005f0300002900000060030000290000006103000029000000620300002900000063030000290000006403000029000000650300002900000066030000290000006703000029000000680300002900000069030000290000006a030000290000006b030000290000006c030000290000006d030000290000006e030000290000006f0300002900000070030000290000007103000029000000720300002900000073030000290000007403000029000000750300002900000076030000290000007703000029000000780300002900000079030000290000007a030000290000007b030000290000007c030000290000007d030000290000007e030000290000007f0300002900000080030000290000008103000029000000820300002900000083030000290000008403000029000000850300002900000086030000290000008703000029000000880300002900000089030000290000008a030000290000008b030000290000008c030000290000008d030000290000008e030000290000000100000000000000040000000000000008000000000000001000000000000000200010000000000040000000250000008f0300002500000090030000250000009103000025000000920300002500000093030000250000009403000025000000950300002500000096030000250000009703000025000000980300002500000099030000250000009a030000250000009b030000250000009c030000250000009d03000025000000
A testdata/golden/res/QueryClientIds.reply.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb reply via raw socketpair tee to an independent reference request
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+01000a0006000000020000000000000000000000000000000000000000000000000000000100000000000000000020000100000000000000
A testdata/golden/xfixes/QueryVersion.reply.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb reply via raw socketpair tee to an independent reference request
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+0100020000000000060000000000000000000000000000000000000000000000
A testdata/golden/xproto/GetGeometry.reply.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb reply via raw socketpair tee to an independent reference request
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+01180400000000009f0300000000000020035802000000000000000000000000
A testdata/golden/xproto/GetProperty.reply.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb reply via raw socketpair tee to an independent reference request
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+01080700010000001f000000000000000300000000000000000000000000000061626300
A testdata/golden/xproto/GetPropertyEmpty.reply.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb reply via raw socketpair tee to an independent reference request
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+0100170000000000000000000000000000000000000000000000000000000000
A testdata/golden/xproto/GetWindowAttributes.reply.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb reply via raw socketpair tee to an independent reference request
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+01001500030000002100000001000001ffffffff000000000101000020000000000000000000000000000000
A testdata/golden/xproto/InternAtom.reply.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb reply via raw socketpair tee to an independent reference request
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+0100050000000000e70000000000000000000000000000000000000000000000
A testdata/golden/xproto/ListExtensions.reply.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb reply via raw socketpair tee to an independent reference request
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+01171800370000000000000000000000000000000000000000000000000000001747656e65726963204576656e7420457874656e73696f6e055348415045074d49542d53484d0f58496e707574457874656e73696f6e0558544553540c4249472d52455155455354530453594e4309584b4559424f4152440758432d4d495343085345435552495459065846495845530652454e4445520552414e44520858494e4552414d4109436f6d706f736974650644414d414745104d49542d53435245454e2d53415645520d444f55424c452d425546464552065245434f52440750726573656e740a582d5265736f757263650658566964656f03474c5800
A testdata/golden/xproto/QueryExtension.reply.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb reply via raw socketpair tee to an independent reference request
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+0100010000000000018a578c0000000000000000000000000000000000000000
A testdata/golden/xproto/QueryTree.reply.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb reply via raw socketpair tee to an independent reference request
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+01001600020000009f03000000000000020000000000000000000000000000000200200001002000
A xcmisc/replies_fuzz_test.go +60 -0
@@ -0,0 +1,60 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package xcmisc
3+
4+import "testing"
5+
6+func FuzzParseGetVersionReply(f *testing.F) {
7+ f.Add(make([]byte, 32))
8+ f.Fuzz(func(t *testing.T, raw []byte) {
9+ r, ok := ParseGetVersionReply(raw)
10+ if !ok {
11+ if len(raw) >= 32 {
12+ t.Fatal("rejected a complete fixed-size reply")
13+ }
14+ return
15+ }
16+ if len(r.Raw()) != len(raw) {
17+ t.Fatal("Raw must return the parsed bytes")
18+ }
19+ _ = r.ServerMajorVersion()
20+ _ = r.ServerMinorVersion()
21+ })
22+}
23+
24+func FuzzParseGetXIDRangeReply(f *testing.F) {
25+ f.Add(make([]byte, 32))
26+ f.Fuzz(func(t *testing.T, raw []byte) {
27+ r, ok := ParseGetXIDRangeReply(raw)
28+ if !ok {
29+ if len(raw) >= 32 {
30+ t.Fatal("rejected a complete fixed-size reply")
31+ }
32+ return
33+ }
34+ if len(r.Raw()) != len(raw) {
35+ t.Fatal("Raw must return the parsed bytes")
36+ }
37+ _ = r.StartId()
38+ _ = r.Count()
39+ })
40+}
41+
42+func FuzzParseGetXIDListReply(f *testing.F) {
43+ f.Add(make([]byte, 32))
44+ f.Fuzz(func(t *testing.T, raw []byte) {
45+ r, ok := ParseGetXIDListReply(raw)
46+ if !ok {
47+ return
48+ }
49+ if len(r.Raw()) != len(raw) {
50+ t.Fatal("Raw must return the parsed bytes")
51+ }
52+ _ = r.IdsLen()
53+ {
54+ l0 := r.Ids()
55+ for i := 0; i < l0.Len(); i++ {
56+ _ = l0.At(i)
57+ }
58+ }
59+ })
60+}
A xcmisc/replies_generated.go +80 -0
@@ -0,0 +1,80 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package xcmisc
3+
4+import "encoding/binary"
5+
6+// GetVersionReply is a zero-copy view over a GetVersion reply; offsets count from reply byte 0.
7+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
8+type GetVersionReply struct{ raw []byte }
9+
10+// ParseGetVersionReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
11+func ParseGetVersionReply(raw []byte) (GetVersionReply, bool) {
12+ if len(raw) < 32 {
13+ return GetVersionReply{}, false
14+ }
15+ r := GetVersionReply{raw: raw}
16+ return r, true
17+}
18+func (r GetVersionReply) Raw() []byte { return r.raw }
19+func (r GetVersionReply) ServerMajorVersion() uint16 {
20+ return uint16(binary.LittleEndian.Uint16(r.raw[8:]))
21+}
22+func (r GetVersionReply) ServerMinorVersion() uint16 {
23+ return uint16(binary.LittleEndian.Uint16(r.raw[10:]))
24+}
25+
26+// GetXIDRangeReply is a zero-copy view over a GetXIDRange reply; offsets count from reply byte 0.
27+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
28+type GetXIDRangeReply struct{ raw []byte }
29+
30+// ParseGetXIDRangeReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
31+func ParseGetXIDRangeReply(raw []byte) (GetXIDRangeReply, bool) {
32+ if len(raw) < 32 {
33+ return GetXIDRangeReply{}, false
34+ }
35+ r := GetXIDRangeReply{raw: raw}
36+ return r, true
37+}
38+func (r GetXIDRangeReply) Raw() []byte { return r.raw }
39+func (r GetXIDRangeReply) StartId() uint32 { return uint32(binary.LittleEndian.Uint32(r.raw[8:])) }
40+func (r GetXIDRangeReply) Count() uint32 { return uint32(binary.LittleEndian.Uint32(r.raw[12:])) }
41+
42+// GetXIDListReply is a zero-copy view over a GetXIDList reply; offsets count from reply byte 0.
43+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
44+type GetXIDListReply struct{ raw []byte }
45+
46+// ParseGetXIDListReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
47+func ParseGetXIDListReply(raw []byte) (GetXIDListReply, bool) {
48+ if len(raw) < 32 {
49+ return GetXIDListReply{}, false
50+ }
51+ r := GetXIDListReply{raw: raw}
52+ off := 32
53+ {
54+ n := int(r.IdsLen())
55+ if n < 0 || n > len(r.raw) {
56+ return GetXIDListReply{}, false
57+ }
58+ off += n * 4
59+ }
60+ if off > len(r.raw) {
61+ return GetXIDListReply{}, false
62+ }
63+ if off > len(r.raw) {
64+ return GetXIDListReply{}, false
65+ }
66+ return r, true
67+}
68+func (r GetXIDListReply) Raw() []byte { return r.raw }
69+func (r GetXIDListReply) IdsLen() uint32 { return uint32(binary.LittleEndian.Uint32(r.raw[8:])) }
70+func (r GetXIDListReply) Ids() Uint32List {
71+ off := 32
72+ end := off + (int(r.IdsLen()))*4
73+ return Uint32List{b: r.raw[off:end:end]}
74+}
75+
76+// Uint32List is a borrowed view over a wire list of uint32. It shares the lifetime of the bytes it was taken from; copy what you keep.
77+type Uint32List struct{ b []byte }
78+
79+func (l Uint32List) Len() int { return len(l.b) / 4 }
80+func (l Uint32List) At(i int) uint32 { return uint32(binary.LittleEndian.Uint32(l.b[i*4:])) }
A xfixes/replies_fuzz_test.go +136 -0
@@ -0,0 +1,136 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package xfixes
3+
4+import "testing"
5+import "bnema.dev/xturbo/internal/xtest"
6+
7+func FuzzParseQueryVersionReply(f *testing.F) {
8+ f.Add(make([]byte, 32))
9+ if raw, err := xtest.LoadHex("../testdata/golden/xfixes/QueryVersion.reply.hex"); err != nil {
10+ f.Fatal(err)
11+ } else {
12+ f.Add(raw)
13+ }
14+ f.Fuzz(func(t *testing.T, raw []byte) {
15+ r, ok := ParseQueryVersionReply(raw)
16+ if !ok {
17+ if len(raw) >= 32 {
18+ t.Fatal("rejected a complete fixed-size reply")
19+ }
20+ return
21+ }
22+ if len(r.Raw()) != len(raw) {
23+ t.Fatal("Raw must return the parsed bytes")
24+ }
25+ _ = r.MajorVersion()
26+ _ = r.MinorVersion()
27+ })
28+}
29+
30+func FuzzParseGetCursorImageReply(f *testing.F) {
31+ f.Add(make([]byte, 32))
32+ f.Fuzz(func(t *testing.T, raw []byte) {
33+ r, ok := ParseGetCursorImageReply(raw)
34+ if !ok {
35+ return
36+ }
37+ if len(r.Raw()) != len(raw) {
38+ t.Fatal("Raw must return the parsed bytes")
39+ }
40+ _ = r.X()
41+ _ = r.Y()
42+ _ = r.Width()
43+ _ = r.Height()
44+ _ = r.Xhot()
45+ _ = r.Yhot()
46+ _ = r.CursorSerial()
47+ {
48+ l0 := r.CursorImage()
49+ for i := 0; i < l0.Len(); i++ {
50+ _ = l0.At(i)
51+ }
52+ }
53+ })
54+}
55+
56+func FuzzParseFetchRegionReply(f *testing.F) {
57+ f.Add(make([]byte, 32))
58+ f.Fuzz(func(t *testing.T, raw []byte) {
59+ r, ok := ParseFetchRegionReply(raw)
60+ if !ok {
61+ return
62+ }
63+ if len(r.Raw()) != len(raw) {
64+ t.Fatal("Raw must return the parsed bytes")
65+ }
66+ _ = r.Extents()
67+ {
68+ l0 := r.Rectangles()
69+ for i := 0; i < l0.Len(); i++ {
70+ _ = l0.At(i)
71+ }
72+ }
73+ })
74+}
75+
76+func FuzzParseGetCursorNameReply(f *testing.F) {
77+ f.Add(make([]byte, 32))
78+ f.Fuzz(func(t *testing.T, raw []byte) {
79+ r, ok := ParseGetCursorNameReply(raw)
80+ if !ok {
81+ return
82+ }
83+ if len(r.Raw()) != len(raw) {
84+ t.Fatal("Raw must return the parsed bytes")
85+ }
86+ _ = r.Atom()
87+ _ = r.Nbytes()
88+ _ = len(r.Name())
89+ })
90+}
91+
92+func FuzzParseGetCursorImageAndNameReply(f *testing.F) {
93+ f.Add(make([]byte, 32))
94+ f.Fuzz(func(t *testing.T, raw []byte) {
95+ r, ok := ParseGetCursorImageAndNameReply(raw)
96+ if !ok {
97+ return
98+ }
99+ if len(r.Raw()) != len(raw) {
100+ t.Fatal("Raw must return the parsed bytes")
101+ }
102+ _ = r.X()
103+ _ = r.Y()
104+ _ = r.Width()
105+ _ = r.Height()
106+ _ = r.Xhot()
107+ _ = r.Yhot()
108+ _ = r.CursorSerial()
109+ _ = r.CursorAtom()
110+ _ = r.Nbytes()
111+ {
112+ l0 := r.CursorImage()
113+ for i := 0; i < l0.Len(); i++ {
114+ _ = l0.At(i)
115+ }
116+ }
117+ _ = len(r.Name())
118+ })
119+}
120+
121+func FuzzParseGetClientDisconnectModeReply(f *testing.F) {
122+ f.Add(make([]byte, 32))
123+ f.Fuzz(func(t *testing.T, raw []byte) {
124+ r, ok := ParseGetClientDisconnectModeReply(raw)
125+ if !ok {
126+ if len(raw) >= 32 {
127+ t.Fatal("rejected a complete fixed-size reply")
128+ }
129+ return
130+ }
131+ if len(r.Raw()) != len(raw) {
132+ t.Fatal("Raw must return the parsed bytes")
133+ }
134+ _ = r.DisconnectMode()
135+ })
136+}
A xfixes/replies_generated.go +242 -0
@@ -0,0 +1,242 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package xfixes
3+
4+import "bnema.dev/xturbo/xproto"
5+import "encoding/binary"
6+
7+// QueryVersionReply is a zero-copy view over a QueryVersion reply; offsets count from reply byte 0.
8+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
9+type QueryVersionReply struct{ raw []byte }
10+
11+// ParseQueryVersionReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
12+func ParseQueryVersionReply(raw []byte) (QueryVersionReply, bool) {
13+ if len(raw) < 32 {
14+ return QueryVersionReply{}, false
15+ }
16+ r := QueryVersionReply{raw: raw}
17+ return r, true
18+}
19+func (r QueryVersionReply) Raw() []byte { return r.raw }
20+func (r QueryVersionReply) MajorVersion() uint32 {
21+ return uint32(binary.LittleEndian.Uint32(r.raw[8:]))
22+}
23+func (r QueryVersionReply) MinorVersion() uint32 {
24+ return uint32(binary.LittleEndian.Uint32(r.raw[12:]))
25+}
26+
27+// GetCursorImageReply is a zero-copy view over a GetCursorImage reply; offsets count from reply byte 0.
28+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
29+type GetCursorImageReply struct{ raw []byte }
30+
31+// ParseGetCursorImageReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
32+func ParseGetCursorImageReply(raw []byte) (GetCursorImageReply, bool) {
33+ if len(raw) < 32 {
34+ return GetCursorImageReply{}, false
35+ }
36+ r := GetCursorImageReply{raw: raw}
37+ off := 32
38+ {
39+ n := (int(r.Width()) * int(r.Height()))
40+ if n < 0 || n > len(r.raw) {
41+ return GetCursorImageReply{}, false
42+ }
43+ off += n * 4
44+ }
45+ if off > len(r.raw) {
46+ return GetCursorImageReply{}, false
47+ }
48+ if off > len(r.raw) {
49+ return GetCursorImageReply{}, false
50+ }
51+ return r, true
52+}
53+func (r GetCursorImageReply) Raw() []byte { return r.raw }
54+func (r GetCursorImageReply) X() int16 { return int16(binary.LittleEndian.Uint16(r.raw[8:])) }
55+func (r GetCursorImageReply) Y() int16 { return int16(binary.LittleEndian.Uint16(r.raw[10:])) }
56+func (r GetCursorImageReply) Width() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[12:])) }
57+func (r GetCursorImageReply) Height() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[14:])) }
58+func (r GetCursorImageReply) Xhot() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[16:])) }
59+func (r GetCursorImageReply) Yhot() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[18:])) }
60+func (r GetCursorImageReply) CursorSerial() uint32 {
61+ return uint32(binary.LittleEndian.Uint32(r.raw[20:]))
62+}
63+func (r GetCursorImageReply) CursorImage() Uint32List {
64+ off := 32
65+ end := off + (int(r.Width())*int(r.Height()))*4
66+ return Uint32List{b: r.raw[off:end:end]}
67+}
68+
69+// FetchRegionReply is a zero-copy view over a FetchRegion reply; offsets count from reply byte 0.
70+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
71+type FetchRegionReply struct{ raw []byte }
72+
73+// ParseFetchRegionReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
74+func ParseFetchRegionReply(raw []byte) (FetchRegionReply, bool) {
75+ if len(raw) < 32 {
76+ return FetchRegionReply{}, false
77+ }
78+ r := FetchRegionReply{raw: raw}
79+ off := 32
80+ {
81+ n := (int(binary.LittleEndian.Uint32(r.raw[4:])) / 2)
82+ if n < 0 || n > len(r.raw) {
83+ return FetchRegionReply{}, false
84+ }
85+ off += n * 8
86+ }
87+ if off > len(r.raw) {
88+ return FetchRegionReply{}, false
89+ }
90+ if off > len(r.raw) {
91+ return FetchRegionReply{}, false
92+ }
93+ return r, true
94+}
95+func (r FetchRegionReply) Raw() []byte { return r.raw }
96+func (r FetchRegionReply) Extents() xproto.Rectangle { return xproto.GetRectangle(r.raw[8:]) }
97+func (r FetchRegionReply) Rectangles() RectangleList {
98+ off := 32
99+ end := off + (int(binary.LittleEndian.Uint32(r.raw[4:]))/2)*8
100+ return RectangleList{b: r.raw[off:end:end]}
101+}
102+
103+// GetCursorNameReply is a zero-copy view over a GetCursorName reply; offsets count from reply byte 0.
104+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
105+type GetCursorNameReply struct{ raw []byte }
106+
107+// ParseGetCursorNameReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
108+func ParseGetCursorNameReply(raw []byte) (GetCursorNameReply, bool) {
109+ if len(raw) < 32 {
110+ return GetCursorNameReply{}, false
111+ }
112+ r := GetCursorNameReply{raw: raw}
113+ off := 32
114+ {
115+ n := int(r.Nbytes())
116+ if n < 0 || n > len(r.raw) {
117+ return GetCursorNameReply{}, false
118+ }
119+ off += n * 1
120+ }
121+ if off > len(r.raw) {
122+ return GetCursorNameReply{}, false
123+ }
124+ if off > len(r.raw) {
125+ return GetCursorNameReply{}, false
126+ }
127+ return r, true
128+}
129+func (r GetCursorNameReply) Raw() []byte { return r.raw }
130+func (r GetCursorNameReply) Atom() xproto.Atom {
131+ return xproto.Atom(binary.LittleEndian.Uint32(r.raw[8:]))
132+}
133+func (r GetCursorNameReply) Nbytes() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[12:])) }
134+func (r GetCursorNameReply) Name() []byte {
135+ off := 32
136+ end := off + int(r.Nbytes())
137+ return r.raw[off:end:end]
138+}
139+
140+// GetCursorImageAndNameReply is a zero-copy view over a GetCursorImageAndName reply; offsets count from reply byte 0.
141+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
142+type GetCursorImageAndNameReply struct{ raw []byte }
143+
144+// ParseGetCursorImageAndNameReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
145+func ParseGetCursorImageAndNameReply(raw []byte) (GetCursorImageAndNameReply, bool) {
146+ if len(raw) < 32 {
147+ return GetCursorImageAndNameReply{}, false
148+ }
149+ r := GetCursorImageAndNameReply{raw: raw}
150+ off := 32
151+ {
152+ n := (int(r.Width()) * int(r.Height()))
153+ if n < 0 || n > len(r.raw) {
154+ return GetCursorImageAndNameReply{}, false
155+ }
156+ off += n * 4
157+ }
158+ if off > len(r.raw) {
159+ return GetCursorImageAndNameReply{}, false
160+ }
161+ {
162+ n := int(r.Nbytes())
163+ if n < 0 || n > len(r.raw) {
164+ return GetCursorImageAndNameReply{}, false
165+ }
166+ off += n * 1
167+ }
168+ if off > len(r.raw) {
169+ return GetCursorImageAndNameReply{}, false
170+ }
171+ if off > len(r.raw) {
172+ return GetCursorImageAndNameReply{}, false
173+ }
174+ return r, true
175+}
176+func (r GetCursorImageAndNameReply) Raw() []byte { return r.raw }
177+func (r GetCursorImageAndNameReply) X() int16 { return int16(binary.LittleEndian.Uint16(r.raw[8:])) }
178+func (r GetCursorImageAndNameReply) Y() int16 { return int16(binary.LittleEndian.Uint16(r.raw[10:])) }
179+func (r GetCursorImageAndNameReply) Width() uint16 {
180+ return uint16(binary.LittleEndian.Uint16(r.raw[12:]))
181+}
182+func (r GetCursorImageAndNameReply) Height() uint16 {
183+ return uint16(binary.LittleEndian.Uint16(r.raw[14:]))
184+}
185+func (r GetCursorImageAndNameReply) Xhot() uint16 {
186+ return uint16(binary.LittleEndian.Uint16(r.raw[16:]))
187+}
188+func (r GetCursorImageAndNameReply) Yhot() uint16 {
189+ return uint16(binary.LittleEndian.Uint16(r.raw[18:]))
190+}
191+func (r GetCursorImageAndNameReply) CursorSerial() uint32 {
192+ return uint32(binary.LittleEndian.Uint32(r.raw[20:]))
193+}
194+func (r GetCursorImageAndNameReply) CursorAtom() xproto.Atom {
195+ return xproto.Atom(binary.LittleEndian.Uint32(r.raw[24:]))
196+}
197+func (r GetCursorImageAndNameReply) Nbytes() uint16 {
198+ return uint16(binary.LittleEndian.Uint16(r.raw[28:]))
199+}
200+func (r GetCursorImageAndNameReply) CursorImage() Uint32List {
201+ off := 32
202+ end := off + (int(r.Width())*int(r.Height()))*4
203+ return Uint32List{b: r.raw[off:end:end]}
204+}
205+func (r GetCursorImageAndNameReply) Name() []byte {
206+ off := 32
207+ {
208+ n := (int(r.Width()) * int(r.Height()))
209+ off += n * 4
210+ }
211+ end := off + int(r.Nbytes())
212+ return r.raw[off:end:end]
213+}
214+
215+// GetClientDisconnectModeReply is a zero-copy view over a GetClientDisconnectMode reply; offsets count from reply byte 0.
216+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
217+type GetClientDisconnectModeReply struct{ raw []byte }
218+
219+// ParseGetClientDisconnectModeReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
220+func ParseGetClientDisconnectModeReply(raw []byte) (GetClientDisconnectModeReply, bool) {
221+ if len(raw) < 32 {
222+ return GetClientDisconnectModeReply{}, false
223+ }
224+ r := GetClientDisconnectModeReply{raw: raw}
225+ return r, true
226+}
227+func (r GetClientDisconnectModeReply) Raw() []byte { return r.raw }
228+func (r GetClientDisconnectModeReply) DisconnectMode() ClientDisconnectFlags {
229+ return ClientDisconnectFlags(binary.LittleEndian.Uint32(r.raw[8:]))
230+}
231+
232+// RectangleList is a borrowed view over a wire list of xproto.Rectangle. It shares the lifetime of the bytes it was taken from; copy what you keep.
233+type RectangleList struct{ b []byte }
234+
235+func (l RectangleList) Len() int { return len(l.b) / 8 }
236+func (l RectangleList) At(i int) xproto.Rectangle { return xproto.GetRectangle(l.b[i*8:]) }
237+
238+// Uint32List is a borrowed view over a wire list of uint32. It shares the lifetime of the bytes it was taken from; copy what you keep.
239+type Uint32List struct{ b []byte }
240+
241+func (l Uint32List) Len() int { return len(l.b) / 4 }
242+func (l Uint32List) At(i int) uint32 { return uint32(binary.LittleEndian.Uint32(l.b[i*4:])) }
A xproto/replies_fuzz_test.go +895 -0
@@ -0,0 +1,895 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package xproto
3+
4+import "testing"
5+import "bnema.dev/xturbo/internal/xtest"
6+
7+func FuzzParseGetWindowAttributesReply(f *testing.F) {
8+ f.Add(make([]byte, 44))
9+ if raw, err := xtest.LoadHex("../testdata/golden/xproto/GetWindowAttributes.reply.hex"); err != nil {
10+ f.Fatal(err)
11+ } else {
12+ f.Add(raw)
13+ }
14+ f.Fuzz(func(t *testing.T, raw []byte) {
15+ r, ok := ParseGetWindowAttributesReply(raw)
16+ if !ok {
17+ if len(raw) >= 44 {
18+ t.Fatal("rejected a complete fixed-size reply")
19+ }
20+ return
21+ }
22+ if len(r.Raw()) != len(raw) {
23+ t.Fatal("Raw must return the parsed bytes")
24+ }
25+ _ = r.BackingStore()
26+ _ = r.Visual()
27+ _ = r.Class()
28+ _ = r.BitGravity()
29+ _ = r.WinGravity()
30+ _ = r.BackingPlanes()
31+ _ = r.BackingPixel()
32+ _ = r.SaveUnder()
33+ _ = r.MapIsInstalled()
34+ _ = r.MapState()
35+ _ = r.OverrideRedirect()
36+ _ = r.Colormap()
37+ _ = r.AllEventMasks()
38+ _ = r.YourEventMask()
39+ _ = r.DoNotPropagateMask()
40+ })
41+}
42+
43+func FuzzParseGetGeometryReply(f *testing.F) {
44+ f.Add(make([]byte, 32))
45+ if raw, err := xtest.LoadHex("../testdata/golden/xproto/GetGeometry.reply.hex"); err != nil {
46+ f.Fatal(err)
47+ } else {
48+ f.Add(raw)
49+ }
50+ f.Fuzz(func(t *testing.T, raw []byte) {
51+ r, ok := ParseGetGeometryReply(raw)
52+ if !ok {
53+ if len(raw) >= 32 {
54+ t.Fatal("rejected a complete fixed-size reply")
55+ }
56+ return
57+ }
58+ if len(r.Raw()) != len(raw) {
59+ t.Fatal("Raw must return the parsed bytes")
60+ }
61+ _ = r.Depth()
62+ _ = r.Root()
63+ _ = r.X()
64+ _ = r.Y()
65+ _ = r.Width()
66+ _ = r.Height()
67+ _ = r.BorderWidth()
68+ })
69+}
70+
71+func FuzzParseQueryTreeReply(f *testing.F) {
72+ f.Add(make([]byte, 32))
73+ if raw, err := xtest.LoadHex("../testdata/golden/xproto/QueryTree.reply.hex"); err != nil {
74+ f.Fatal(err)
75+ } else {
76+ f.Add(raw)
77+ }
78+ f.Fuzz(func(t *testing.T, raw []byte) {
79+ r, ok := ParseQueryTreeReply(raw)
80+ if !ok {
81+ return
82+ }
83+ if len(r.Raw()) != len(raw) {
84+ t.Fatal("Raw must return the parsed bytes")
85+ }
86+ _ = r.Root()
87+ _ = r.Parent()
88+ _ = r.ChildrenLen()
89+ {
90+ l0 := r.Children()
91+ for i := 0; i < l0.Len(); i++ {
92+ _ = l0.At(i)
93+ }
94+ }
95+ })
96+}
97+
98+func FuzzParseInternAtomReply(f *testing.F) {
99+ f.Add(make([]byte, 32))
100+ if raw, err := xtest.LoadHex("../testdata/golden/xproto/InternAtom.reply.hex"); err != nil {
101+ f.Fatal(err)
102+ } else {
103+ f.Add(raw)
104+ }
105+ f.Fuzz(func(t *testing.T, raw []byte) {
106+ r, ok := ParseInternAtomReply(raw)
107+ if !ok {
108+ if len(raw) >= 32 {
109+ t.Fatal("rejected a complete fixed-size reply")
110+ }
111+ return
112+ }
113+ if len(r.Raw()) != len(raw) {
114+ t.Fatal("Raw must return the parsed bytes")
115+ }
116+ _ = r.Atom()
117+ })
118+}
119+
120+func FuzzParseGetAtomNameReply(f *testing.F) {
121+ f.Add(make([]byte, 32))
122+ f.Fuzz(func(t *testing.T, raw []byte) {
123+ r, ok := ParseGetAtomNameReply(raw)
124+ if !ok {
125+ return
126+ }
127+ if len(r.Raw()) != len(raw) {
128+ t.Fatal("Raw must return the parsed bytes")
129+ }
130+ _ = r.NameLen()
131+ _ = len(r.Name())
132+ })
133+}
134+
135+func FuzzParseGetPropertyReply(f *testing.F) {
136+ f.Add(make([]byte, 32))
137+ if raw, err := xtest.LoadHex("../testdata/golden/xproto/GetProperty.reply.hex"); err != nil {
138+ f.Fatal(err)
139+ } else {
140+ f.Add(raw)
141+ }
142+ if raw, err := xtest.LoadHex("../testdata/golden/xproto/GetPropertyEmpty.reply.hex"); err != nil {
143+ f.Fatal(err)
144+ } else {
145+ f.Add(raw)
146+ }
147+ f.Fuzz(func(t *testing.T, raw []byte) {
148+ r, ok := ParseGetPropertyReply(raw)
149+ if !ok {
150+ return
151+ }
152+ if len(r.Raw()) != len(raw) {
153+ t.Fatal("Raw must return the parsed bytes")
154+ }
155+ _ = r.Format()
156+ _ = r.Type()
157+ _ = r.BytesAfter()
158+ _ = r.ValueLen()
159+ _ = len(r.Value())
160+ })
161+}
162+
163+func FuzzParseListPropertiesReply(f *testing.F) {
164+ f.Add(make([]byte, 32))
165+ f.Fuzz(func(t *testing.T, raw []byte) {
166+ r, ok := ParseListPropertiesReply(raw)
167+ if !ok {
168+ return
169+ }
170+ if len(r.Raw()) != len(raw) {
171+ t.Fatal("Raw must return the parsed bytes")
172+ }
173+ _ = r.AtomsLen()
174+ {
175+ l0 := r.Atoms()
176+ for i := 0; i < l0.Len(); i++ {
177+ _ = l0.At(i)
178+ }
179+ }
180+ })
181+}
182+
183+func FuzzParseGetSelectionOwnerReply(f *testing.F) {
184+ f.Add(make([]byte, 32))
185+ f.Fuzz(func(t *testing.T, raw []byte) {
186+ r, ok := ParseGetSelectionOwnerReply(raw)
187+ if !ok {
188+ if len(raw) >= 32 {
189+ t.Fatal("rejected a complete fixed-size reply")
190+ }
191+ return
192+ }
193+ if len(r.Raw()) != len(raw) {
194+ t.Fatal("Raw must return the parsed bytes")
195+ }
196+ _ = r.Owner()
197+ })
198+}
199+
200+func FuzzParseGrabPointerReply(f *testing.F) {
201+ f.Add(make([]byte, 32))
202+ f.Fuzz(func(t *testing.T, raw []byte) {
203+ r, ok := ParseGrabPointerReply(raw)
204+ if !ok {
205+ if len(raw) >= 32 {
206+ t.Fatal("rejected a complete fixed-size reply")
207+ }
208+ return
209+ }
210+ if len(r.Raw()) != len(raw) {
211+ t.Fatal("Raw must return the parsed bytes")
212+ }
213+ _ = r.Status()
214+ })
215+}
216+
217+func FuzzParseGrabKeyboardReply(f *testing.F) {
218+ f.Add(make([]byte, 32))
219+ f.Fuzz(func(t *testing.T, raw []byte) {
220+ r, ok := ParseGrabKeyboardReply(raw)
221+ if !ok {
222+ if len(raw) >= 32 {
223+ t.Fatal("rejected a complete fixed-size reply")
224+ }
225+ return
226+ }
227+ if len(r.Raw()) != len(raw) {
228+ t.Fatal("Raw must return the parsed bytes")
229+ }
230+ _ = r.Status()
231+ })
232+}
233+
234+func FuzzParseQueryPointerReply(f *testing.F) {
235+ f.Add(make([]byte, 32))
236+ f.Fuzz(func(t *testing.T, raw []byte) {
237+ r, ok := ParseQueryPointerReply(raw)
238+ if !ok {
239+ if len(raw) >= 32 {
240+ t.Fatal("rejected a complete fixed-size reply")
241+ }
242+ return
243+ }
244+ if len(r.Raw()) != len(raw) {
245+ t.Fatal("Raw must return the parsed bytes")
246+ }
247+ _ = r.SameScreen()
248+ _ = r.Root()
249+ _ = r.Child()
250+ _ = r.RootX()
251+ _ = r.RootY()
252+ _ = r.WinX()
253+ _ = r.WinY()
254+ _ = r.Mask()
255+ })
256+}
257+
258+func FuzzParseGetMotionEventsReply(f *testing.F) {
259+ f.Add(make([]byte, 32))
260+ f.Fuzz(func(t *testing.T, raw []byte) {
261+ r, ok := ParseGetMotionEventsReply(raw)
262+ if !ok {
263+ return
264+ }
265+ if len(r.Raw()) != len(raw) {
266+ t.Fatal("Raw must return the parsed bytes")
267+ }
268+ _ = r.EventsLen()
269+ {
270+ l0 := r.Events()
271+ for i := 0; i < l0.Len(); i++ {
272+ _ = l0.At(i)
273+ }
274+ }
275+ })
276+}
277+
278+func FuzzParseTranslateCoordinatesReply(f *testing.F) {
279+ f.Add(make([]byte, 32))
280+ f.Fuzz(func(t *testing.T, raw []byte) {
281+ r, ok := ParseTranslateCoordinatesReply(raw)
282+ if !ok {
283+ if len(raw) >= 32 {
284+ t.Fatal("rejected a complete fixed-size reply")
285+ }
286+ return
287+ }
288+ if len(r.Raw()) != len(raw) {
289+ t.Fatal("Raw must return the parsed bytes")
290+ }
291+ _ = r.SameScreen()
292+ _ = r.Child()
293+ _ = r.DstX()
294+ _ = r.DstY()
295+ })
296+}
297+
298+func FuzzParseGetInputFocusReply(f *testing.F) {
299+ f.Add(make([]byte, 32))
300+ f.Fuzz(func(t *testing.T, raw []byte) {
301+ r, ok := ParseGetInputFocusReply(raw)
302+ if !ok {
303+ if len(raw) >= 32 {
304+ t.Fatal("rejected a complete fixed-size reply")
305+ }
306+ return
307+ }
308+ if len(r.Raw()) != len(raw) {
309+ t.Fatal("Raw must return the parsed bytes")
310+ }
311+ _ = r.RevertTo()
312+ _ = r.Focus()
313+ })
314+}
315+
316+func FuzzParseQueryKeymapReply(f *testing.F) {
317+ f.Add(make([]byte, 40))
318+ f.Fuzz(func(t *testing.T, raw []byte) {
319+ r, ok := ParseQueryKeymapReply(raw)
320+ if !ok {
321+ if len(raw) >= 40 {
322+ t.Fatal("rejected a complete fixed-size reply")
323+ }
324+ return
325+ }
326+ if len(r.Raw()) != len(raw) {
327+ t.Fatal("Raw must return the parsed bytes")
328+ }
329+ _ = len(r.Keys())
330+ })
331+}
332+
333+func FuzzParseQueryFontReply(f *testing.F) {
334+ f.Add(make([]byte, 60))
335+ f.Fuzz(func(t *testing.T, raw []byte) {
336+ r, ok := ParseQueryFontReply(raw)
337+ if !ok {
338+ return
339+ }
340+ if len(r.Raw()) != len(raw) {
341+ t.Fatal("Raw must return the parsed bytes")
342+ }
343+ _ = r.MinBounds()
344+ _ = r.MaxBounds()
345+ _ = r.MinCharOrByte2()
346+ _ = r.MaxCharOrByte2()
347+ _ = r.DefaultChar()
348+ _ = r.PropertiesLen()
349+ _ = r.DrawDirection()
350+ _ = r.MinByte1()
351+ _ = r.MaxByte1()
352+ _ = r.AllCharsExist()
353+ _ = r.FontAscent()
354+ _ = r.FontDescent()
355+ _ = r.CharInfosLen()
356+ {
357+ l0 := r.Properties()
358+ for i := 0; i < l0.Len(); i++ {
359+ _ = l0.At(i)
360+ }
361+ }
362+ {
363+ l0 := r.CharInfos()
364+ for i := 0; i < l0.Len(); i++ {
365+ _ = l0.At(i)
366+ }
367+ }
368+ })
369+}
370+
371+func FuzzParseQueryTextExtentsReply(f *testing.F) {
372+ f.Add(make([]byte, 32))
373+ f.Fuzz(func(t *testing.T, raw []byte) {
374+ r, ok := ParseQueryTextExtentsReply(raw)
375+ if !ok {
376+ if len(raw) >= 32 {
377+ t.Fatal("rejected a complete fixed-size reply")
378+ }
379+ return
380+ }
381+ if len(r.Raw()) != len(raw) {
382+ t.Fatal("Raw must return the parsed bytes")
383+ }
384+ _ = r.DrawDirection()
385+ _ = r.FontAscent()
386+ _ = r.FontDescent()
387+ _ = r.OverallAscent()
388+ _ = r.OverallDescent()
389+ _ = r.OverallWidth()
390+ _ = r.OverallLeft()
391+ _ = r.OverallRight()
392+ })
393+}
394+
395+func FuzzParseListFontsReply(f *testing.F) {
396+ f.Add(make([]byte, 32))
397+ f.Fuzz(func(t *testing.T, raw []byte) {
398+ r, ok := ParseListFontsReply(raw)
399+ if !ok {
400+ return
401+ }
402+ if len(r.Raw()) != len(raw) {
403+ t.Fatal("Raw must return the parsed bytes")
404+ }
405+ _ = r.NamesLen()
406+ {
407+ it0 := r.Names()
408+ for it0.Next() {
409+ _ = it0.Value().NameLen()
410+ _ = len(it0.Value().Name())
411+ }
412+ if it0.Err() {
413+ t.Fatal("iterator error after successful Parse")
414+ }
415+ }
416+ })
417+}
418+
419+func FuzzParseListFontsWithInfoReply(f *testing.F) {
420+ f.Add(make([]byte, 60))
421+ f.Fuzz(func(t *testing.T, raw []byte) {
422+ r, ok := ParseListFontsWithInfoReply(raw)
423+ if !ok {
424+ return
425+ }
426+ if len(r.Raw()) != len(raw) {
427+ t.Fatal("Raw must return the parsed bytes")
428+ }
429+ _ = r.NameLen()
430+ _ = r.MinBounds()
431+ _ = r.MaxBounds()
432+ _ = r.MinCharOrByte2()
433+ _ = r.MaxCharOrByte2()
434+ _ = r.DefaultChar()
435+ _ = r.PropertiesLen()
436+ _ = r.DrawDirection()
437+ _ = r.MinByte1()
438+ _ = r.MaxByte1()
439+ _ = r.AllCharsExist()
440+ _ = r.FontAscent()
441+ _ = r.FontDescent()
442+ _ = r.RepliesHint()
443+ {
444+ l0 := r.Properties()
445+ for i := 0; i < l0.Len(); i++ {
446+ _ = l0.At(i)
447+ }
448+ }
449+ _ = len(r.Name())
450+ })
451+}
452+
453+func FuzzParseGetFontPathReply(f *testing.F) {
454+ f.Add(make([]byte, 32))
455+ f.Fuzz(func(t *testing.T, raw []byte) {
456+ r, ok := ParseGetFontPathReply(raw)
457+ if !ok {
458+ return
459+ }
460+ if len(r.Raw()) != len(raw) {
461+ t.Fatal("Raw must return the parsed bytes")
462+ }
463+ _ = r.PathLen()
464+ {
465+ it0 := r.Path()
466+ for it0.Next() {
467+ _ = it0.Value().NameLen()
468+ _ = len(it0.Value().Name())
469+ }
470+ if it0.Err() {
471+ t.Fatal("iterator error after successful Parse")
472+ }
473+ }
474+ })
475+}
476+
477+func FuzzParseGetImageReply(f *testing.F) {
478+ f.Add(make([]byte, 32))
479+ f.Fuzz(func(t *testing.T, raw []byte) {
480+ r, ok := ParseGetImageReply(raw)
481+ if !ok {
482+ return
483+ }
484+ if len(r.Raw()) != len(raw) {
485+ t.Fatal("Raw must return the parsed bytes")
486+ }
487+ _ = r.Depth()
488+ _ = r.Visual()
489+ _ = len(r.Data())
490+ })
491+}
492+
493+func FuzzParseListInstalledColormapsReply(f *testing.F) {
494+ f.Add(make([]byte, 32))
495+ f.Fuzz(func(t *testing.T, raw []byte) {
496+ r, ok := ParseListInstalledColormapsReply(raw)
497+ if !ok {
498+ return
499+ }
500+ if len(r.Raw()) != len(raw) {
501+ t.Fatal("Raw must return the parsed bytes")
502+ }
503+ _ = r.CmapsLen()
504+ {
505+ l0 := r.Cmaps()
506+ for i := 0; i < l0.Len(); i++ {
507+ _ = l0.At(i)
508+ }
509+ }
510+ })
511+}
512+
513+func FuzzParseAllocColorReply(f *testing.F) {
514+ f.Add(make([]byte, 32))
515+ f.Fuzz(func(t *testing.T, raw []byte) {
516+ r, ok := ParseAllocColorReply(raw)
517+ if !ok {
518+ if len(raw) >= 32 {
519+ t.Fatal("rejected a complete fixed-size reply")
520+ }
521+ return
522+ }
523+ if len(r.Raw()) != len(raw) {
524+ t.Fatal("Raw must return the parsed bytes")
525+ }
526+ _ = r.Red()
527+ _ = r.Green()
528+ _ = r.Blue()
529+ _ = r.Pixel()
530+ })
531+}
532+
533+func FuzzParseAllocNamedColorReply(f *testing.F) {
534+ f.Add(make([]byte, 32))
535+ f.Fuzz(func(t *testing.T, raw []byte) {
536+ r, ok := ParseAllocNamedColorReply(raw)
537+ if !ok {
538+ if len(raw) >= 32 {
539+ t.Fatal("rejected a complete fixed-size reply")
540+ }
541+ return
542+ }
543+ if len(r.Raw()) != len(raw) {
544+ t.Fatal("Raw must return the parsed bytes")
545+ }
546+ _ = r.Pixel()
547+ _ = r.ExactRed()
548+ _ = r.ExactGreen()
549+ _ = r.ExactBlue()
550+ _ = r.VisualRed()
551+ _ = r.VisualGreen()
552+ _ = r.VisualBlue()
553+ })
554+}
555+
556+func FuzzParseAllocColorCellsReply(f *testing.F) {
557+ f.Add(make([]byte, 32))
558+ f.Fuzz(func(t *testing.T, raw []byte) {
559+ r, ok := ParseAllocColorCellsReply(raw)
560+ if !ok {
561+ return
562+ }
563+ if len(r.Raw()) != len(raw) {
564+ t.Fatal("Raw must return the parsed bytes")
565+ }
566+ _ = r.PixelsLen()
567+ _ = r.MasksLen()
568+ {
569+ l0 := r.Pixels()
570+ for i := 0; i < l0.Len(); i++ {
571+ _ = l0.At(i)
572+ }
573+ }
574+ {
575+ l0 := r.Masks()
576+ for i := 0; i < l0.Len(); i++ {
577+ _ = l0.At(i)
578+ }
579+ }
580+ })
581+}
582+
583+func FuzzParseAllocColorPlanesReply(f *testing.F) {
584+ f.Add(make([]byte, 32))
585+ f.Fuzz(func(t *testing.T, raw []byte) {
586+ r, ok := ParseAllocColorPlanesReply(raw)
587+ if !ok {
588+ return
589+ }
590+ if len(r.Raw()) != len(raw) {
591+ t.Fatal("Raw must return the parsed bytes")
592+ }
593+ _ = r.PixelsLen()
594+ _ = r.RedMask()
595+ _ = r.GreenMask()
596+ _ = r.BlueMask()
597+ {
598+ l0 := r.Pixels()
599+ for i := 0; i < l0.Len(); i++ {
600+ _ = l0.At(i)
601+ }
602+ }
603+ })
604+}
605+
606+func FuzzParseQueryColorsReply(f *testing.F) {
607+ f.Add(make([]byte, 32))
608+ f.Fuzz(func(t *testing.T, raw []byte) {
609+ r, ok := ParseQueryColorsReply(raw)
610+ if !ok {
611+ return
612+ }
613+ if len(r.Raw()) != len(raw) {
614+ t.Fatal("Raw must return the parsed bytes")
615+ }
616+ _ = r.ColorsLen()
617+ {
618+ l0 := r.Colors()
619+ for i := 0; i < l0.Len(); i++ {
620+ _ = l0.At(i)
621+ }
622+ }
623+ })
624+}
625+
626+func FuzzParseLookupColorReply(f *testing.F) {
627+ f.Add(make([]byte, 32))
628+ f.Fuzz(func(t *testing.T, raw []byte) {
629+ r, ok := ParseLookupColorReply(raw)
630+ if !ok {
631+ if len(raw) >= 32 {
632+ t.Fatal("rejected a complete fixed-size reply")
633+ }
634+ return
635+ }
636+ if len(r.Raw()) != len(raw) {
637+ t.Fatal("Raw must return the parsed bytes")
638+ }
639+ _ = r.ExactRed()
640+ _ = r.ExactGreen()
641+ _ = r.ExactBlue()
642+ _ = r.VisualRed()
643+ _ = r.VisualGreen()
644+ _ = r.VisualBlue()
645+ })
646+}
647+
648+func FuzzParseQueryBestSizeReply(f *testing.F) {
649+ f.Add(make([]byte, 32))
650+ f.Fuzz(func(t *testing.T, raw []byte) {
651+ r, ok := ParseQueryBestSizeReply(raw)
652+ if !ok {
653+ if len(raw) >= 32 {
654+ t.Fatal("rejected a complete fixed-size reply")
655+ }
656+ return
657+ }
658+ if len(r.Raw()) != len(raw) {
659+ t.Fatal("Raw must return the parsed bytes")
660+ }
661+ _ = r.Width()
662+ _ = r.Height()
663+ })
664+}
665+
666+func FuzzParseQueryExtensionReply(f *testing.F) {
667+ f.Add(make([]byte, 32))
668+ if raw, err := xtest.LoadHex("../testdata/golden/xproto/QueryExtension.reply.hex"); err != nil {
669+ f.Fatal(err)
670+ } else {
671+ f.Add(raw)
672+ }
673+ f.Fuzz(func(t *testing.T, raw []byte) {
674+ r, ok := ParseQueryExtensionReply(raw)
675+ if !ok {
676+ if len(raw) >= 32 {
677+ t.Fatal("rejected a complete fixed-size reply")
678+ }
679+ return
680+ }
681+ if len(r.Raw()) != len(raw) {
682+ t.Fatal("Raw must return the parsed bytes")
683+ }
684+ _ = r.Present()
685+ _ = r.MajorOpcode()
686+ _ = r.FirstEvent()
687+ _ = r.FirstError()
688+ })
689+}
690+
691+func FuzzParseListExtensionsReply(f *testing.F) {
692+ f.Add(make([]byte, 32))
693+ if raw, err := xtest.LoadHex("../testdata/golden/xproto/ListExtensions.reply.hex"); err != nil {
694+ f.Fatal(err)
695+ } else {
696+ f.Add(raw)
697+ }
698+ f.Fuzz(func(t *testing.T, raw []byte) {
699+ r, ok := ParseListExtensionsReply(raw)
700+ if !ok {
701+ return
702+ }
703+ if len(r.Raw()) != len(raw) {
704+ t.Fatal("Raw must return the parsed bytes")
705+ }
706+ _ = r.NamesLen()
707+ {
708+ it0 := r.Names()
709+ for it0.Next() {
710+ _ = it0.Value().NameLen()
711+ _ = len(it0.Value().Name())
712+ }
713+ if it0.Err() {
714+ t.Fatal("iterator error after successful Parse")
715+ }
716+ }
717+ })
718+}
719+
720+func FuzzParseGetKeyboardMappingReply(f *testing.F) {
721+ f.Add(make([]byte, 32))
722+ f.Fuzz(func(t *testing.T, raw []byte) {
723+ r, ok := ParseGetKeyboardMappingReply(raw)
724+ if !ok {
725+ return
726+ }
727+ if len(r.Raw()) != len(raw) {
728+ t.Fatal("Raw must return the parsed bytes")
729+ }
730+ _ = r.KeysymsPerKeycode()
731+ {
732+ l0 := r.Keysyms()
733+ for i := 0; i < l0.Len(); i++ {
734+ _ = l0.At(i)
735+ }
736+ }
737+ })
738+}
739+
740+func FuzzParseGetKeyboardControlReply(f *testing.F) {
741+ f.Add(make([]byte, 52))
742+ f.Fuzz(func(t *testing.T, raw []byte) {
743+ r, ok := ParseGetKeyboardControlReply(raw)
744+ if !ok {
745+ if len(raw) >= 52 {
746+ t.Fatal("rejected a complete fixed-size reply")
747+ }
748+ return
749+ }
750+ if len(r.Raw()) != len(raw) {
751+ t.Fatal("Raw must return the parsed bytes")
752+ }
753+ _ = r.GlobalAutoRepeat()
754+ _ = r.LedMask()
755+ _ = r.KeyClickPercent()
756+ _ = r.BellPercent()
757+ _ = r.BellPitch()
758+ _ = r.BellDuration()
759+ _ = len(r.AutoRepeats())
760+ })
761+}
762+
763+func FuzzParseGetPointerControlReply(f *testing.F) {
764+ f.Add(make([]byte, 32))
765+ f.Fuzz(func(t *testing.T, raw []byte) {
766+ r, ok := ParseGetPointerControlReply(raw)
767+ if !ok {
768+ if len(raw) >= 32 {
769+ t.Fatal("rejected a complete fixed-size reply")
770+ }
771+ return
772+ }
773+ if len(r.Raw()) != len(raw) {
774+ t.Fatal("Raw must return the parsed bytes")
775+ }
776+ _ = r.AccelerationNumerator()
777+ _ = r.AccelerationDenominator()
778+ _ = r.Threshold()
779+ })
780+}
781+
782+func FuzzParseGetScreenSaverReply(f *testing.F) {
783+ f.Add(make([]byte, 32))
784+ f.Fuzz(func(t *testing.T, raw []byte) {
785+ r, ok := ParseGetScreenSaverReply(raw)
786+ if !ok {
787+ if len(raw) >= 32 {
788+ t.Fatal("rejected a complete fixed-size reply")
789+ }
790+ return
791+ }
792+ if len(r.Raw()) != len(raw) {
793+ t.Fatal("Raw must return the parsed bytes")
794+ }
795+ _ = r.Timeout()
796+ _ = r.Interval()
797+ _ = r.PreferBlanking()
798+ _ = r.AllowExposures()
799+ })
800+}
801+
802+func FuzzParseListHostsReply(f *testing.F) {
803+ f.Add(make([]byte, 32))
804+ f.Fuzz(func(t *testing.T, raw []byte) {
805+ r, ok := ParseListHostsReply(raw)
806+ if !ok {
807+ return
808+ }
809+ if len(r.Raw()) != len(raw) {
810+ t.Fatal("Raw must return the parsed bytes")
811+ }
812+ _ = r.Mode()
813+ _ = r.HostsLen()
814+ {
815+ it0 := r.Hosts()
816+ for it0.Next() {
817+ _ = it0.Value().Family()
818+ _ = it0.Value().AddressLen()
819+ _ = len(it0.Value().Address())
820+ }
821+ if it0.Err() {
822+ t.Fatal("iterator error after successful Parse")
823+ }
824+ }
825+ })
826+}
827+
828+func FuzzParseSetPointerMappingReply(f *testing.F) {
829+ f.Add(make([]byte, 32))
830+ f.Fuzz(func(t *testing.T, raw []byte) {
831+ r, ok := ParseSetPointerMappingReply(raw)
832+ if !ok {
833+ if len(raw) >= 32 {
834+ t.Fatal("rejected a complete fixed-size reply")
835+ }
836+ return
837+ }
838+ if len(r.Raw()) != len(raw) {
839+ t.Fatal("Raw must return the parsed bytes")
840+ }
841+ _ = r.Status()
842+ })
843+}
844+
845+func FuzzParseGetPointerMappingReply(f *testing.F) {
846+ f.Add(make([]byte, 32))
847+ f.Fuzz(func(t *testing.T, raw []byte) {
848+ r, ok := ParseGetPointerMappingReply(raw)
849+ if !ok {
850+ return
851+ }
852+ if len(r.Raw()) != len(raw) {
853+ t.Fatal("Raw must return the parsed bytes")
854+ }
855+ _ = r.MapLen()
856+ _ = len(r.Map())
857+ })
858+}
859+
860+func FuzzParseSetModifierMappingReply(f *testing.F) {
861+ f.Add(make([]byte, 32))
862+ f.Fuzz(func(t *testing.T, raw []byte) {
863+ r, ok := ParseSetModifierMappingReply(raw)
864+ if !ok {
865+ if len(raw) >= 32 {
866+ t.Fatal("rejected a complete fixed-size reply")
867+ }
868+ return
869+ }
870+ if len(r.Raw()) != len(raw) {
871+ t.Fatal("Raw must return the parsed bytes")
872+ }
873+ _ = r.Status()
874+ })
875+}
876+
877+func FuzzParseGetModifierMappingReply(f *testing.F) {
878+ f.Add(make([]byte, 32))
879+ f.Fuzz(func(t *testing.T, raw []byte) {
880+ r, ok := ParseGetModifierMappingReply(raw)
881+ if !ok {
882+ return
883+ }
884+ if len(r.Raw()) != len(raw) {
885+ t.Fatal("Raw must return the parsed bytes")
886+ }
887+ _ = r.KeycodesPerModifier()
888+ {
889+ l0 := r.Keycodes()
890+ for i := 0; i < l0.Len(); i++ {
891+ _ = l0.At(i)
892+ }
893+ }
894+ })
895+}
A xproto/replies_generated.go +1964 -0
@@ -0,0 +1,1964 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package xproto
3+
4+import "encoding/binary"
5+
6+// GetWindowAttributesReply is a zero-copy view over a GetWindowAttributes reply; offsets count from reply byte 0.
7+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
8+type GetWindowAttributesReply struct{ raw []byte }
9+
10+// ParseGetWindowAttributesReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
11+func ParseGetWindowAttributesReply(raw []byte) (GetWindowAttributesReply, bool) {
12+ if len(raw) < 44 {
13+ return GetWindowAttributesReply{}, false
14+ }
15+ r := GetWindowAttributesReply{raw: raw}
16+ return r, true
17+}
18+func (r GetWindowAttributesReply) Raw() []byte { return r.raw }
19+func (r GetWindowAttributesReply) BackingStore() BackingStore { return BackingStore(r.raw[1:][0]) }
20+func (r GetWindowAttributesReply) Visual() Visualid {
21+ return Visualid(binary.LittleEndian.Uint32(r.raw[8:]))
22+}
23+func (r GetWindowAttributesReply) Class() WindowClass {
24+ return WindowClass(binary.LittleEndian.Uint16(r.raw[12:]))
25+}
26+func (r GetWindowAttributesReply) BitGravity() Gravity { return Gravity(r.raw[14:][0]) }
27+func (r GetWindowAttributesReply) WinGravity() Gravity { return Gravity(r.raw[15:][0]) }
28+func (r GetWindowAttributesReply) BackingPlanes() uint32 {
29+ return uint32(binary.LittleEndian.Uint32(r.raw[16:]))
30+}
31+func (r GetWindowAttributesReply) BackingPixel() uint32 {
32+ return uint32(binary.LittleEndian.Uint32(r.raw[20:]))
33+}
34+func (r GetWindowAttributesReply) SaveUnder() bool { return (r.raw[24:][0] != 0) }
35+func (r GetWindowAttributesReply) MapIsInstalled() bool { return (r.raw[25:][0] != 0) }
36+func (r GetWindowAttributesReply) MapState() MapState { return MapState(r.raw[26:][0]) }
37+func (r GetWindowAttributesReply) OverrideRedirect() bool { return (r.raw[27:][0] != 0) }
38+func (r GetWindowAttributesReply) Colormap() Colormap {
39+ return Colormap(binary.LittleEndian.Uint32(r.raw[28:]))
40+}
41+func (r GetWindowAttributesReply) AllEventMasks() EventMask {
42+ return EventMask(binary.LittleEndian.Uint32(r.raw[32:]))
43+}
44+func (r GetWindowAttributesReply) YourEventMask() EventMask {
45+ return EventMask(binary.LittleEndian.Uint32(r.raw[36:]))
46+}
47+func (r GetWindowAttributesReply) DoNotPropagateMask() EventMask {
48+ return EventMask(binary.LittleEndian.Uint16(r.raw[40:]))
49+}
50+
51+// GetGeometryReply is a zero-copy view over a GetGeometry reply; offsets count from reply byte 0.
52+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
53+type GetGeometryReply struct{ raw []byte }
54+
55+// ParseGetGeometryReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
56+func ParseGetGeometryReply(raw []byte) (GetGeometryReply, bool) {
57+ if len(raw) < 32 {
58+ return GetGeometryReply{}, false
59+ }
60+ r := GetGeometryReply{raw: raw}
61+ return r, true
62+}
63+func (r GetGeometryReply) Raw() []byte { return r.raw }
64+func (r GetGeometryReply) Depth() uint8 { return uint8(r.raw[1:][0]) }
65+func (r GetGeometryReply) Root() Window { return Window(binary.LittleEndian.Uint32(r.raw[8:])) }
66+func (r GetGeometryReply) X() int16 { return int16(binary.LittleEndian.Uint16(r.raw[12:])) }
67+func (r GetGeometryReply) Y() int16 { return int16(binary.LittleEndian.Uint16(r.raw[14:])) }
68+func (r GetGeometryReply) Width() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[16:])) }
69+func (r GetGeometryReply) Height() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[18:])) }
70+func (r GetGeometryReply) BorderWidth() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[20:])) }
71+
72+// QueryTreeReply is a zero-copy view over a QueryTree reply; offsets count from reply byte 0.
73+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
74+type QueryTreeReply struct{ raw []byte }
75+
76+// ParseQueryTreeReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
77+func ParseQueryTreeReply(raw []byte) (QueryTreeReply, bool) {
78+ if len(raw) < 32 {
79+ return QueryTreeReply{}, false
80+ }
81+ r := QueryTreeReply{raw: raw}
82+ off := 32
83+ {
84+ n := int(r.ChildrenLen())
85+ if n < 0 || n > len(r.raw) {
86+ return QueryTreeReply{}, false
87+ }
88+ off += n * 4
89+ }
90+ if off > len(r.raw) {
91+ return QueryTreeReply{}, false
92+ }
93+ if off > len(r.raw) {
94+ return QueryTreeReply{}, false
95+ }
96+ return r, true
97+}
98+func (r QueryTreeReply) Raw() []byte { return r.raw }
99+func (r QueryTreeReply) Root() Window { return Window(binary.LittleEndian.Uint32(r.raw[8:])) }
100+func (r QueryTreeReply) Parent() Window { return Window(binary.LittleEndian.Uint32(r.raw[12:])) }
101+func (r QueryTreeReply) ChildrenLen() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[16:])) }
102+func (r QueryTreeReply) Children() WindowList {
103+ off := 32
104+ end := off + (int(r.ChildrenLen()))*4
105+ return WindowList{b: r.raw[off:end:end]}
106+}
107+
108+// InternAtomReply is a zero-copy view over a InternAtom reply; offsets count from reply byte 0.
109+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
110+type InternAtomReply struct{ raw []byte }
111+
112+// ParseInternAtomReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
113+func ParseInternAtomReply(raw []byte) (InternAtomReply, bool) {
114+ if len(raw) < 32 {
115+ return InternAtomReply{}, false
116+ }
117+ r := InternAtomReply{raw: raw}
118+ return r, true
119+}
120+func (r InternAtomReply) Raw() []byte { return r.raw }
121+func (r InternAtomReply) Atom() Atom { return Atom(binary.LittleEndian.Uint32(r.raw[8:])) }
122+
123+// GetAtomNameReply is a zero-copy view over a GetAtomName reply; offsets count from reply byte 0.
124+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
125+type GetAtomNameReply struct{ raw []byte }
126+
127+// ParseGetAtomNameReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
128+func ParseGetAtomNameReply(raw []byte) (GetAtomNameReply, bool) {
129+ if len(raw) < 32 {
130+ return GetAtomNameReply{}, false
131+ }
132+ r := GetAtomNameReply{raw: raw}
133+ off := 32
134+ {
135+ n := int(r.NameLen())
136+ if n < 0 || n > len(r.raw) {
137+ return GetAtomNameReply{}, false
138+ }
139+ off += n * 1
140+ }
141+ if off > len(r.raw) {
142+ return GetAtomNameReply{}, false
143+ }
144+ if off > len(r.raw) {
145+ return GetAtomNameReply{}, false
146+ }
147+ return r, true
148+}
149+func (r GetAtomNameReply) Raw() []byte { return r.raw }
150+func (r GetAtomNameReply) NameLen() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[8:])) }
151+func (r GetAtomNameReply) Name() []byte {
152+ off := 32
153+ end := off + int(r.NameLen())
154+ return r.raw[off:end:end]
155+}
156+
157+// GetPropertyReply is a zero-copy view over a GetProperty reply; offsets count from reply byte 0.
158+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
159+type GetPropertyReply struct{ raw []byte }
160+
161+// ParseGetPropertyReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
162+func ParseGetPropertyReply(raw []byte) (GetPropertyReply, bool) {
163+ if len(raw) < 32 {
164+ return GetPropertyReply{}, false
165+ }
166+ r := GetPropertyReply{raw: raw}
167+ off := 32
168+ {
169+ n := (int(r.ValueLen()) * (int(r.Format()) / 8))
170+ if n < 0 || n > len(r.raw) {
171+ return GetPropertyReply{}, false
172+ }
173+ off += n * 1
174+ }
175+ if off > len(r.raw) {
176+ return GetPropertyReply{}, false
177+ }
178+ if off > len(r.raw) {
179+ return GetPropertyReply{}, false
180+ }
181+ return r, true
182+}
183+func (r GetPropertyReply) Raw() []byte { return r.raw }
184+func (r GetPropertyReply) Format() uint8 { return uint8(r.raw[1:][0]) }
185+func (r GetPropertyReply) Type() Atom { return Atom(binary.LittleEndian.Uint32(r.raw[8:])) }
186+func (r GetPropertyReply) BytesAfter() uint32 { return uint32(binary.LittleEndian.Uint32(r.raw[12:])) }
187+func (r GetPropertyReply) ValueLen() uint32 { return uint32(binary.LittleEndian.Uint32(r.raw[16:])) }
188+func (r GetPropertyReply) Value() []byte {
189+ off := 32
190+ end := off + (int(r.ValueLen()) * (int(r.Format()) / 8))
191+ return r.raw[off:end:end]
192+}
193+
194+// ListPropertiesReply is a zero-copy view over a ListProperties reply; offsets count from reply byte 0.
195+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
196+type ListPropertiesReply struct{ raw []byte }
197+
198+// ParseListPropertiesReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
199+func ParseListPropertiesReply(raw []byte) (ListPropertiesReply, bool) {
200+ if len(raw) < 32 {
201+ return ListPropertiesReply{}, false
202+ }
203+ r := ListPropertiesReply{raw: raw}
204+ off := 32
205+ {
206+ n := int(r.AtomsLen())
207+ if n < 0 || n > len(r.raw) {
208+ return ListPropertiesReply{}, false
209+ }
210+ off += n * 4
211+ }
212+ if off > len(r.raw) {
213+ return ListPropertiesReply{}, false
214+ }
215+ if off > len(r.raw) {
216+ return ListPropertiesReply{}, false
217+ }
218+ return r, true
219+}
220+func (r ListPropertiesReply) Raw() []byte { return r.raw }
221+func (r ListPropertiesReply) AtomsLen() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[8:])) }
222+func (r ListPropertiesReply) Atoms() AtomList {
223+ off := 32
224+ end := off + (int(r.AtomsLen()))*4
225+ return AtomList{b: r.raw[off:end:end]}
226+}
227+
228+// GetSelectionOwnerReply is a zero-copy view over a GetSelectionOwner reply; offsets count from reply byte 0.
229+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
230+type GetSelectionOwnerReply struct{ raw []byte }
231+
232+// ParseGetSelectionOwnerReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
233+func ParseGetSelectionOwnerReply(raw []byte) (GetSelectionOwnerReply, bool) {
234+ if len(raw) < 32 {
235+ return GetSelectionOwnerReply{}, false
236+ }
237+ r := GetSelectionOwnerReply{raw: raw}
238+ return r, true
239+}
240+func (r GetSelectionOwnerReply) Raw() []byte { return r.raw }
241+func (r GetSelectionOwnerReply) Owner() Window { return Window(binary.LittleEndian.Uint32(r.raw[8:])) }
242+
243+// GrabPointerReply is a zero-copy view over a GrabPointer reply; offsets count from reply byte 0.
244+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
245+type GrabPointerReply struct{ raw []byte }
246+
247+// ParseGrabPointerReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
248+func ParseGrabPointerReply(raw []byte) (GrabPointerReply, bool) {
249+ if len(raw) < 32 {
250+ return GrabPointerReply{}, false
251+ }
252+ r := GrabPointerReply{raw: raw}
253+ return r, true
254+}
255+func (r GrabPointerReply) Raw() []byte { return r.raw }
256+func (r GrabPointerReply) Status() GrabStatus { return GrabStatus(r.raw[1:][0]) }
257+
258+// GrabKeyboardReply is a zero-copy view over a GrabKeyboard reply; offsets count from reply byte 0.
259+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
260+type GrabKeyboardReply struct{ raw []byte }
261+
262+// ParseGrabKeyboardReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
263+func ParseGrabKeyboardReply(raw []byte) (GrabKeyboardReply, bool) {
264+ if len(raw) < 32 {
265+ return GrabKeyboardReply{}, false
266+ }
267+ r := GrabKeyboardReply{raw: raw}
268+ return r, true
269+}
270+func (r GrabKeyboardReply) Raw() []byte { return r.raw }
271+func (r GrabKeyboardReply) Status() GrabStatus { return GrabStatus(r.raw[1:][0]) }
272+
273+// QueryPointerReply is a zero-copy view over a QueryPointer reply; offsets count from reply byte 0.
274+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
275+type QueryPointerReply struct{ raw []byte }
276+
277+// ParseQueryPointerReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
278+func ParseQueryPointerReply(raw []byte) (QueryPointerReply, bool) {
279+ if len(raw) < 32 {
280+ return QueryPointerReply{}, false
281+ }
282+ r := QueryPointerReply{raw: raw}
283+ return r, true
284+}
285+func (r QueryPointerReply) Raw() []byte { return r.raw }
286+func (r QueryPointerReply) SameScreen() bool { return (r.raw[1:][0] != 0) }
287+func (r QueryPointerReply) Root() Window { return Window(binary.LittleEndian.Uint32(r.raw[8:])) }
288+func (r QueryPointerReply) Child() Window { return Window(binary.LittleEndian.Uint32(r.raw[12:])) }
289+func (r QueryPointerReply) RootX() int16 { return int16(binary.LittleEndian.Uint16(r.raw[16:])) }
290+func (r QueryPointerReply) RootY() int16 { return int16(binary.LittleEndian.Uint16(r.raw[18:])) }
291+func (r QueryPointerReply) WinX() int16 { return int16(binary.LittleEndian.Uint16(r.raw[20:])) }
292+func (r QueryPointerReply) WinY() int16 { return int16(binary.LittleEndian.Uint16(r.raw[22:])) }
293+func (r QueryPointerReply) Mask() KeyButMask {
294+ return KeyButMask(binary.LittleEndian.Uint16(r.raw[24:]))
295+}
296+
297+// GetMotionEventsReply is a zero-copy view over a GetMotionEvents reply; offsets count from reply byte 0.
298+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
299+type GetMotionEventsReply struct{ raw []byte }
300+
301+// ParseGetMotionEventsReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
302+func ParseGetMotionEventsReply(raw []byte) (GetMotionEventsReply, bool) {
303+ if len(raw) < 32 {
304+ return GetMotionEventsReply{}, false
305+ }
306+ r := GetMotionEventsReply{raw: raw}
307+ off := 32
308+ {
309+ n := int(r.EventsLen())
310+ if n < 0 || n > len(r.raw) {
311+ return GetMotionEventsReply{}, false
312+ }
313+ off += n * 8
314+ }
315+ if off > len(r.raw) {
316+ return GetMotionEventsReply{}, false
317+ }
318+ if off > len(r.raw) {
319+ return GetMotionEventsReply{}, false
320+ }
321+ return r, true
322+}
323+func (r GetMotionEventsReply) Raw() []byte { return r.raw }
324+func (r GetMotionEventsReply) EventsLen() uint32 {
325+ return uint32(binary.LittleEndian.Uint32(r.raw[8:]))
326+}
327+func (r GetMotionEventsReply) Events() TimecoordList {
328+ off := 32
329+ end := off + (int(r.EventsLen()))*8
330+ return TimecoordList{b: r.raw[off:end:end]}
331+}
332+
333+// TranslateCoordinatesReply is a zero-copy view over a TranslateCoordinates reply; offsets count from reply byte 0.
334+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
335+type TranslateCoordinatesReply struct{ raw []byte }
336+
337+// ParseTranslateCoordinatesReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
338+func ParseTranslateCoordinatesReply(raw []byte) (TranslateCoordinatesReply, bool) {
339+ if len(raw) < 32 {
340+ return TranslateCoordinatesReply{}, false
341+ }
342+ r := TranslateCoordinatesReply{raw: raw}
343+ return r, true
344+}
345+func (r TranslateCoordinatesReply) Raw() []byte { return r.raw }
346+func (r TranslateCoordinatesReply) SameScreen() bool { return (r.raw[1:][0] != 0) }
347+func (r TranslateCoordinatesReply) Child() Window {
348+ return Window(binary.LittleEndian.Uint32(r.raw[8:]))
349+}
350+func (r TranslateCoordinatesReply) DstX() int16 { return int16(binary.LittleEndian.Uint16(r.raw[12:])) }
351+func (r TranslateCoordinatesReply) DstY() int16 { return int16(binary.LittleEndian.Uint16(r.raw[14:])) }
352+
353+// GetInputFocusReply is a zero-copy view over a GetInputFocus reply; offsets count from reply byte 0.
354+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
355+type GetInputFocusReply struct{ raw []byte }
356+
357+// ParseGetInputFocusReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
358+func ParseGetInputFocusReply(raw []byte) (GetInputFocusReply, bool) {
359+ if len(raw) < 32 {
360+ return GetInputFocusReply{}, false
361+ }
362+ r := GetInputFocusReply{raw: raw}
363+ return r, true
364+}
365+func (r GetInputFocusReply) Raw() []byte { return r.raw }
366+func (r GetInputFocusReply) RevertTo() InputFocus { return InputFocus(r.raw[1:][0]) }
367+func (r GetInputFocusReply) Focus() Window { return Window(binary.LittleEndian.Uint32(r.raw[8:])) }
368+
369+// QueryKeymapReply is a zero-copy view over a QueryKeymap reply; offsets count from reply byte 0.
370+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
371+type QueryKeymapReply struct{ raw []byte }
372+
373+// ParseQueryKeymapReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
374+func ParseQueryKeymapReply(raw []byte) (QueryKeymapReply, bool) {
375+ if len(raw) < 40 {
376+ return QueryKeymapReply{}, false
377+ }
378+ r := QueryKeymapReply{raw: raw}
379+ return r, true
380+}
381+func (r QueryKeymapReply) Raw() []byte { return r.raw }
382+func (r QueryKeymapReply) Keys() []byte { off := 8; end := off + 32; return r.raw[off:end:end] }
383+
384+// QueryFontReply is a zero-copy view over a QueryFont reply; offsets count from reply byte 0.
385+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
386+type QueryFontReply struct{ raw []byte }
387+
388+// ParseQueryFontReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
389+func ParseQueryFontReply(raw []byte) (QueryFontReply, bool) {
390+ if len(raw) < 60 {
391+ return QueryFontReply{}, false
392+ }
393+ r := QueryFontReply{raw: raw}
394+ off := 60
395+ {
396+ n := int(r.PropertiesLen())
397+ if n < 0 || n > len(r.raw) {
398+ return QueryFontReply{}, false
399+ }
400+ off += n * 8
401+ }
402+ if off > len(r.raw) {
403+ return QueryFontReply{}, false
404+ }
405+ {
406+ n := int(r.CharInfosLen())
407+ if n < 0 || n > len(r.raw) {
408+ return QueryFontReply{}, false
409+ }
410+ off += n * 12
411+ }
412+ if off > len(r.raw) {
413+ return QueryFontReply{}, false
414+ }
415+ if off > len(r.raw) {
416+ return QueryFontReply{}, false
417+ }
418+ return r, true
419+}
420+func (r QueryFontReply) Raw() []byte { return r.raw }
421+func (r QueryFontReply) MinBounds() Charinfo { return GetCharinfo(r.raw[8:]) }
422+func (r QueryFontReply) MaxBounds() Charinfo { return GetCharinfo(r.raw[24:]) }
423+func (r QueryFontReply) MinCharOrByte2() uint16 {
424+ return uint16(binary.LittleEndian.Uint16(r.raw[40:]))
425+}
426+func (r QueryFontReply) MaxCharOrByte2() uint16 {
427+ return uint16(binary.LittleEndian.Uint16(r.raw[42:]))
428+}
429+func (r QueryFontReply) DefaultChar() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[44:])) }
430+func (r QueryFontReply) PropertiesLen() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[46:])) }
431+func (r QueryFontReply) DrawDirection() FontDraw { return FontDraw(r.raw[48:][0]) }
432+func (r QueryFontReply) MinByte1() uint8 { return uint8(r.raw[49:][0]) }
433+func (r QueryFontReply) MaxByte1() uint8 { return uint8(r.raw[50:][0]) }
434+func (r QueryFontReply) AllCharsExist() bool { return (r.raw[51:][0] != 0) }
435+func (r QueryFontReply) FontAscent() int16 { return int16(binary.LittleEndian.Uint16(r.raw[52:])) }
436+func (r QueryFontReply) FontDescent() int16 { return int16(binary.LittleEndian.Uint16(r.raw[54:])) }
437+func (r QueryFontReply) CharInfosLen() uint32 { return uint32(binary.LittleEndian.Uint32(r.raw[56:])) }
438+func (r QueryFontReply) Properties() FontpropList {
439+ off := 60
440+ end := off + (int(r.PropertiesLen()))*8
441+ return FontpropList{b: r.raw[off:end:end]}
442+}
443+func (r QueryFontReply) CharInfos() CharinfoList {
444+ off := 60
445+ {
446+ n := int(r.PropertiesLen())
447+ off += n * 8
448+ }
449+ end := off + (int(r.CharInfosLen()))*12
450+ return CharinfoList{b: r.raw[off:end:end]}
451+}
452+
453+// QueryTextExtentsReply is a zero-copy view over a QueryTextExtents reply; offsets count from reply byte 0.
454+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
455+type QueryTextExtentsReply struct{ raw []byte }
456+
457+// ParseQueryTextExtentsReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
458+func ParseQueryTextExtentsReply(raw []byte) (QueryTextExtentsReply, bool) {
459+ if len(raw) < 32 {
460+ return QueryTextExtentsReply{}, false
461+ }
462+ r := QueryTextExtentsReply{raw: raw}
463+ return r, true
464+}
465+func (r QueryTextExtentsReply) Raw() []byte { return r.raw }
466+func (r QueryTextExtentsReply) DrawDirection() FontDraw { return FontDraw(r.raw[1:][0]) }
467+func (r QueryTextExtentsReply) FontAscent() int16 {
468+ return int16(binary.LittleEndian.Uint16(r.raw[8:]))
469+}
470+func (r QueryTextExtentsReply) FontDescent() int16 {
471+ return int16(binary.LittleEndian.Uint16(r.raw[10:]))
472+}
473+func (r QueryTextExtentsReply) OverallAscent() int16 {
474+ return int16(binary.LittleEndian.Uint16(r.raw[12:]))
475+}
476+func (r QueryTextExtentsReply) OverallDescent() int16 {
477+ return int16(binary.LittleEndian.Uint16(r.raw[14:]))
478+}
479+func (r QueryTextExtentsReply) OverallWidth() int32 {
480+ return int32(binary.LittleEndian.Uint32(r.raw[16:]))
481+}
482+func (r QueryTextExtentsReply) OverallLeft() int32 {
483+ return int32(binary.LittleEndian.Uint32(r.raw[20:]))
484+}
485+func (r QueryTextExtentsReply) OverallRight() int32 {
486+ return int32(binary.LittleEndian.Uint32(r.raw[24:]))
487+}
488+
489+// ListFontsReply is a zero-copy view over a ListFonts reply; offsets count from reply byte 0.
490+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
491+type ListFontsReply struct{ raw []byte }
492+
493+// ParseListFontsReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
494+func ParseListFontsReply(raw []byte) (ListFontsReply, bool) {
495+ if len(raw) < 32 {
496+ return ListFontsReply{}, false
497+ }
498+ r := ListFontsReply{raw: raw}
499+ off := 32
500+ {
501+ n := int(r.NamesLen())
502+ if off > len(r.raw) || n < 0 || n > len(r.raw) {
503+ return ListFontsReply{}, false
504+ }
505+ it := NewStrIter(r.raw[off:], n)
506+ for it.Next() {
507+ off += it.Value().Size()
508+ }
509+ if it.Err() {
510+ return ListFontsReply{}, false
511+ }
512+ }
513+ if off > len(r.raw) {
514+ return ListFontsReply{}, false
515+ }
516+ return r, true
517+}
518+func (r ListFontsReply) Raw() []byte { return r.raw }
519+func (r ListFontsReply) NamesLen() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[8:])) }
520+func (r ListFontsReply) Names() StrIter { off := 32; return NewStrIter(r.raw[off:], int(r.NamesLen())) }
521+
522+// ListFontsWithInfoReply is a zero-copy view over a ListFontsWithInfo reply; offsets count from reply byte 0.
523+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
524+type ListFontsWithInfoReply struct{ raw []byte }
525+
526+// ParseListFontsWithInfoReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
527+func ParseListFontsWithInfoReply(raw []byte) (ListFontsWithInfoReply, bool) {
528+ if len(raw) < 60 {
529+ return ListFontsWithInfoReply{}, false
530+ }
531+ r := ListFontsWithInfoReply{raw: raw}
532+ off := 60
533+ {
534+ n := int(r.PropertiesLen())
535+ if n < 0 || n > len(r.raw) {
536+ return ListFontsWithInfoReply{}, false
537+ }
538+ off += n * 8
539+ }
540+ if off > len(r.raw) {
541+ return ListFontsWithInfoReply{}, false
542+ }
543+ {
544+ n := int(r.NameLen())
545+ if n < 0 || n > len(r.raw) {
546+ return ListFontsWithInfoReply{}, false
547+ }
548+ off += n * 1
549+ }
550+ if off > len(r.raw) {
551+ return ListFontsWithInfoReply{}, false
552+ }
553+ if off > len(r.raw) {
554+ return ListFontsWithInfoReply{}, false
555+ }
556+ return r, true
557+}
558+func (r ListFontsWithInfoReply) Raw() []byte { return r.raw }
559+func (r ListFontsWithInfoReply) NameLen() uint8 { return uint8(r.raw[1:][0]) }
560+func (r ListFontsWithInfoReply) MinBounds() Charinfo { return GetCharinfo(r.raw[8:]) }
561+func (r ListFontsWithInfoReply) MaxBounds() Charinfo { return GetCharinfo(r.raw[24:]) }
562+func (r ListFontsWithInfoReply) MinCharOrByte2() uint16 {
563+ return uint16(binary.LittleEndian.Uint16(r.raw[40:]))
564+}
565+func (r ListFontsWithInfoReply) MaxCharOrByte2() uint16 {
566+ return uint16(binary.LittleEndian.Uint16(r.raw[42:]))
567+}
568+func (r ListFontsWithInfoReply) DefaultChar() uint16 {
569+ return uint16(binary.LittleEndian.Uint16(r.raw[44:]))
570+}
571+func (r ListFontsWithInfoReply) PropertiesLen() uint16 {
572+ return uint16(binary.LittleEndian.Uint16(r.raw[46:]))
573+}
574+func (r ListFontsWithInfoReply) DrawDirection() FontDraw { return FontDraw(r.raw[48:][0]) }
575+func (r ListFontsWithInfoReply) MinByte1() uint8 { return uint8(r.raw[49:][0]) }
576+func (r ListFontsWithInfoReply) MaxByte1() uint8 { return uint8(r.raw[50:][0]) }
577+func (r ListFontsWithInfoReply) AllCharsExist() bool { return (r.raw[51:][0] != 0) }
578+func (r ListFontsWithInfoReply) FontAscent() int16 {
579+ return int16(binary.LittleEndian.Uint16(r.raw[52:]))
580+}
581+func (r ListFontsWithInfoReply) FontDescent() int16 {
582+ return int16(binary.LittleEndian.Uint16(r.raw[54:]))
583+}
584+func (r ListFontsWithInfoReply) RepliesHint() uint32 {
585+ return uint32(binary.LittleEndian.Uint32(r.raw[56:]))
586+}
587+func (r ListFontsWithInfoReply) Properties() FontpropList {
588+ off := 60
589+ end := off + (int(r.PropertiesLen()))*8
590+ return FontpropList{b: r.raw[off:end:end]}
591+}
592+func (r ListFontsWithInfoReply) Name() []byte {
593+ off := 60
594+ {
595+ n := int(r.PropertiesLen())
596+ off += n * 8
597+ }
598+ end := off + int(r.NameLen())
599+ return r.raw[off:end:end]
600+}
601+
602+// GetFontPathReply is a zero-copy view over a GetFontPath reply; offsets count from reply byte 0.
603+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
604+type GetFontPathReply struct{ raw []byte }
605+
606+// ParseGetFontPathReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
607+func ParseGetFontPathReply(raw []byte) (GetFontPathReply, bool) {
608+ if len(raw) < 32 {
609+ return GetFontPathReply{}, false
610+ }
611+ r := GetFontPathReply{raw: raw}
612+ off := 32
613+ {
614+ n := int(r.PathLen())
615+ if off > len(r.raw) || n < 0 || n > len(r.raw) {
616+ return GetFontPathReply{}, false
617+ }
618+ it := NewStrIter(r.raw[off:], n)
619+ for it.Next() {
620+ off += it.Value().Size()
621+ }
622+ if it.Err() {
623+ return GetFontPathReply{}, false
624+ }
625+ }
626+ if off > len(r.raw) {
627+ return GetFontPathReply{}, false
628+ }
629+ return r, true
630+}
631+func (r GetFontPathReply) Raw() []byte { return r.raw }
632+func (r GetFontPathReply) PathLen() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[8:])) }
633+func (r GetFontPathReply) Path() StrIter { off := 32; return NewStrIter(r.raw[off:], int(r.PathLen())) }
634+
635+// GetImageReply is a zero-copy view over a GetImage reply; offsets count from reply byte 0.
636+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
637+type GetImageReply struct{ raw []byte }
638+
639+// ParseGetImageReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
640+func ParseGetImageReply(raw []byte) (GetImageReply, bool) {
641+ if len(raw) < 32 {
642+ return GetImageReply{}, false
643+ }
644+ r := GetImageReply{raw: raw}
645+ off := 32
646+ {
647+ n := (int(binary.LittleEndian.Uint32(r.raw[4:])) * 4)
648+ if n < 0 || n > len(r.raw) {
649+ return GetImageReply{}, false
650+ }
651+ off += n * 1
652+ }
653+ if off > len(r.raw) {
654+ return GetImageReply{}, false
655+ }
656+ if off > len(r.raw) {
657+ return GetImageReply{}, false
658+ }
659+ return r, true
660+}
661+func (r GetImageReply) Raw() []byte { return r.raw }
662+func (r GetImageReply) Depth() uint8 { return uint8(r.raw[1:][0]) }
663+func (r GetImageReply) Visual() Visualid { return Visualid(binary.LittleEndian.Uint32(r.raw[8:])) }
664+func (r GetImageReply) Data() []byte {
665+ off := 32
666+ end := off + (int(binary.LittleEndian.Uint32(r.raw[4:])) * 4)
667+ return r.raw[off:end:end]
668+}
669+
670+// ListInstalledColormapsReply is a zero-copy view over a ListInstalledColormaps reply; offsets count from reply byte 0.
671+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
672+type ListInstalledColormapsReply struct{ raw []byte }
673+
674+// ParseListInstalledColormapsReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
675+func ParseListInstalledColormapsReply(raw []byte) (ListInstalledColormapsReply, bool) {
676+ if len(raw) < 32 {
677+ return ListInstalledColormapsReply{}, false
678+ }
679+ r := ListInstalledColormapsReply{raw: raw}
680+ off := 32
681+ {
682+ n := int(r.CmapsLen())
683+ if n < 0 || n > len(r.raw) {
684+ return ListInstalledColormapsReply{}, false
685+ }
686+ off += n * 4
687+ }
688+ if off > len(r.raw) {
689+ return ListInstalledColormapsReply{}, false
690+ }
691+ if off > len(r.raw) {
692+ return ListInstalledColormapsReply{}, false
693+ }
694+ return r, true
695+}
696+func (r ListInstalledColormapsReply) Raw() []byte { return r.raw }
697+func (r ListInstalledColormapsReply) CmapsLen() uint16 {
698+ return uint16(binary.LittleEndian.Uint16(r.raw[8:]))
699+}
700+func (r ListInstalledColormapsReply) Cmaps() ColormapList {
701+ off := 32
702+ end := off + (int(r.CmapsLen()))*4
703+ return ColormapList{b: r.raw[off:end:end]}
704+}
705+
706+// AllocColorReply is a zero-copy view over a AllocColor reply; offsets count from reply byte 0.
707+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
708+type AllocColorReply struct{ raw []byte }
709+
710+// ParseAllocColorReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
711+func ParseAllocColorReply(raw []byte) (AllocColorReply, bool) {
712+ if len(raw) < 32 {
713+ return AllocColorReply{}, false
714+ }
715+ r := AllocColorReply{raw: raw}
716+ return r, true
717+}
718+func (r AllocColorReply) Raw() []byte { return r.raw }
719+func (r AllocColorReply) Red() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[8:])) }
720+func (r AllocColorReply) Green() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[10:])) }
721+func (r AllocColorReply) Blue() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[12:])) }
722+func (r AllocColorReply) Pixel() uint32 { return uint32(binary.LittleEndian.Uint32(r.raw[16:])) }
723+
724+// AllocNamedColorReply is a zero-copy view over a AllocNamedColor reply; offsets count from reply byte 0.
725+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
726+type AllocNamedColorReply struct{ raw []byte }
727+
728+// ParseAllocNamedColorReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
729+func ParseAllocNamedColorReply(raw []byte) (AllocNamedColorReply, bool) {
730+ if len(raw) < 32 {
731+ return AllocNamedColorReply{}, false
732+ }
733+ r := AllocNamedColorReply{raw: raw}
734+ return r, true
735+}
736+func (r AllocNamedColorReply) Raw() []byte { return r.raw }
737+func (r AllocNamedColorReply) Pixel() uint32 { return uint32(binary.LittleEndian.Uint32(r.raw[8:])) }
738+func (r AllocNamedColorReply) ExactRed() uint16 {
739+ return uint16(binary.LittleEndian.Uint16(r.raw[12:]))
740+}
741+func (r AllocNamedColorReply) ExactGreen() uint16 {
742+ return uint16(binary.LittleEndian.Uint16(r.raw[14:]))
743+}
744+func (r AllocNamedColorReply) ExactBlue() uint16 {
745+ return uint16(binary.LittleEndian.Uint16(r.raw[16:]))
746+}
747+func (r AllocNamedColorReply) VisualRed() uint16 {
748+ return uint16(binary.LittleEndian.Uint16(r.raw[18:]))
749+}
750+func (r AllocNamedColorReply) VisualGreen() uint16 {
751+ return uint16(binary.LittleEndian.Uint16(r.raw[20:]))
752+}
753+func (r AllocNamedColorReply) VisualBlue() uint16 {
754+ return uint16(binary.LittleEndian.Uint16(r.raw[22:]))
755+}
756+
757+// AllocColorCellsReply is a zero-copy view over a AllocColorCells reply; offsets count from reply byte 0.
758+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
759+type AllocColorCellsReply struct{ raw []byte }
760+
761+// ParseAllocColorCellsReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
762+func ParseAllocColorCellsReply(raw []byte) (AllocColorCellsReply, bool) {
763+ if len(raw) < 32 {
764+ return AllocColorCellsReply{}, false
765+ }
766+ r := AllocColorCellsReply{raw: raw}
767+ off := 32
768+ {
769+ n := int(r.PixelsLen())
770+ if n < 0 || n > len(r.raw) {
771+ return AllocColorCellsReply{}, false
772+ }
773+ off += n * 4
774+ }
775+ if off > len(r.raw) {
776+ return AllocColorCellsReply{}, false
777+ }
778+ {
779+ n := int(r.MasksLen())
780+ if n < 0 || n > len(r.raw) {
781+ return AllocColorCellsReply{}, false
782+ }
783+ off += n * 4
784+ }
785+ if off > len(r.raw) {
786+ return AllocColorCellsReply{}, false
787+ }
788+ if off > len(r.raw) {
789+ return AllocColorCellsReply{}, false
790+ }
791+ return r, true
792+}
793+func (r AllocColorCellsReply) Raw() []byte { return r.raw }
794+func (r AllocColorCellsReply) PixelsLen() uint16 {
795+ return uint16(binary.LittleEndian.Uint16(r.raw[8:]))
796+}
797+func (r AllocColorCellsReply) MasksLen() uint16 {
798+ return uint16(binary.LittleEndian.Uint16(r.raw[10:]))
799+}
800+func (r AllocColorCellsReply) Pixels() Uint32List {
801+ off := 32
802+ end := off + (int(r.PixelsLen()))*4
803+ return Uint32List{b: r.raw[off:end:end]}
804+}
805+func (r AllocColorCellsReply) Masks() Uint32List {
806+ off := 32
807+ {
808+ n := int(r.PixelsLen())
809+ off += n * 4
810+ }
811+ end := off + (int(r.MasksLen()))*4
812+ return Uint32List{b: r.raw[off:end:end]}
813+}
814+
815+// AllocColorPlanesReply is a zero-copy view over a AllocColorPlanes reply; offsets count from reply byte 0.
816+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
817+type AllocColorPlanesReply struct{ raw []byte }
818+
819+// ParseAllocColorPlanesReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
820+func ParseAllocColorPlanesReply(raw []byte) (AllocColorPlanesReply, bool) {
821+ if len(raw) < 32 {
822+ return AllocColorPlanesReply{}, false
823+ }
824+ r := AllocColorPlanesReply{raw: raw}
825+ off := 32
826+ {
827+ n := int(r.PixelsLen())
828+ if n < 0 || n > len(r.raw) {
829+ return AllocColorPlanesReply{}, false
830+ }
831+ off += n * 4
832+ }
833+ if off > len(r.raw) {
834+ return AllocColorPlanesReply{}, false
835+ }
836+ if off > len(r.raw) {
837+ return AllocColorPlanesReply{}, false
838+ }
839+ return r, true
840+}
841+func (r AllocColorPlanesReply) Raw() []byte { return r.raw }
842+func (r AllocColorPlanesReply) PixelsLen() uint16 {
843+ return uint16(binary.LittleEndian.Uint16(r.raw[8:]))
844+}
845+func (r AllocColorPlanesReply) RedMask() uint32 {
846+ return uint32(binary.LittleEndian.Uint32(r.raw[12:]))
847+}
848+func (r AllocColorPlanesReply) GreenMask() uint32 {
849+ return uint32(binary.LittleEndian.Uint32(r.raw[16:]))
850+}
851+func (r AllocColorPlanesReply) BlueMask() uint32 {
852+ return uint32(binary.LittleEndian.Uint32(r.raw[20:]))
853+}
854+func (r AllocColorPlanesReply) Pixels() Uint32List {
855+ off := 32
856+ end := off + (int(r.PixelsLen()))*4
857+ return Uint32List{b: r.raw[off:end:end]}
858+}
859+
860+// QueryColorsReply is a zero-copy view over a QueryColors reply; offsets count from reply byte 0.
861+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
862+type QueryColorsReply struct{ raw []byte }
863+
864+// ParseQueryColorsReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
865+func ParseQueryColorsReply(raw []byte) (QueryColorsReply, bool) {
866+ if len(raw) < 32 {
867+ return QueryColorsReply{}, false
868+ }
869+ r := QueryColorsReply{raw: raw}
870+ off := 32
871+ {
872+ n := int(r.ColorsLen())
873+ if n < 0 || n > len(r.raw) {
874+ return QueryColorsReply{}, false
875+ }
876+ off += n * 8
877+ }
878+ if off > len(r.raw) {
879+ return QueryColorsReply{}, false
880+ }
881+ if off > len(r.raw) {
882+ return QueryColorsReply{}, false
883+ }
884+ return r, true
885+}
886+func (r QueryColorsReply) Raw() []byte { return r.raw }
887+func (r QueryColorsReply) ColorsLen() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[8:])) }
888+func (r QueryColorsReply) Colors() RgbList {
889+ off := 32
890+ end := off + (int(r.ColorsLen()))*8
891+ return RgbList{b: r.raw[off:end:end]}
892+}
893+
894+// LookupColorReply is a zero-copy view over a LookupColor reply; offsets count from reply byte 0.
895+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
896+type LookupColorReply struct{ raw []byte }
897+
898+// ParseLookupColorReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
899+func ParseLookupColorReply(raw []byte) (LookupColorReply, bool) {
900+ if len(raw) < 32 {
901+ return LookupColorReply{}, false
902+ }
903+ r := LookupColorReply{raw: raw}
904+ return r, true
905+}
906+func (r LookupColorReply) Raw() []byte { return r.raw }
907+func (r LookupColorReply) ExactRed() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[8:])) }
908+func (r LookupColorReply) ExactGreen() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[10:])) }
909+func (r LookupColorReply) ExactBlue() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[12:])) }
910+func (r LookupColorReply) VisualRed() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[14:])) }
911+func (r LookupColorReply) VisualGreen() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[16:])) }
912+func (r LookupColorReply) VisualBlue() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[18:])) }
913+
914+// QueryBestSizeReply is a zero-copy view over a QueryBestSize reply; offsets count from reply byte 0.
915+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
916+type QueryBestSizeReply struct{ raw []byte }
917+
918+// ParseQueryBestSizeReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
919+func ParseQueryBestSizeReply(raw []byte) (QueryBestSizeReply, bool) {
920+ if len(raw) < 32 {
921+ return QueryBestSizeReply{}, false
922+ }
923+ r := QueryBestSizeReply{raw: raw}
924+ return r, true
925+}
926+func (r QueryBestSizeReply) Raw() []byte { return r.raw }
927+func (r QueryBestSizeReply) Width() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[8:])) }
928+func (r QueryBestSizeReply) Height() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[10:])) }
929+
930+// QueryExtensionReply is a zero-copy view over a QueryExtension reply; offsets count from reply byte 0.
931+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
932+type QueryExtensionReply struct{ raw []byte }
933+
934+// ParseQueryExtensionReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
935+func ParseQueryExtensionReply(raw []byte) (QueryExtensionReply, bool) {
936+ if len(raw) < 32 {
937+ return QueryExtensionReply{}, false
938+ }
939+ r := QueryExtensionReply{raw: raw}
940+ return r, true
941+}
942+func (r QueryExtensionReply) Raw() []byte { return r.raw }
943+func (r QueryExtensionReply) Present() bool { return (r.raw[8:][0] != 0) }
944+func (r QueryExtensionReply) MajorOpcode() uint8 { return uint8(r.raw[9:][0]) }
945+func (r QueryExtensionReply) FirstEvent() uint8 { return uint8(r.raw[10:][0]) }
946+func (r QueryExtensionReply) FirstError() uint8 { return uint8(r.raw[11:][0]) }
947+
948+// ListExtensionsReply is a zero-copy view over a ListExtensions reply; offsets count from reply byte 0.
949+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
950+type ListExtensionsReply struct{ raw []byte }
951+
952+// ParseListExtensionsReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
953+func ParseListExtensionsReply(raw []byte) (ListExtensionsReply, bool) {
954+ if len(raw) < 32 {
955+ return ListExtensionsReply{}, false
956+ }
957+ r := ListExtensionsReply{raw: raw}
958+ off := 32
959+ {
960+ n := int(r.NamesLen())
961+ if off > len(r.raw) || n < 0 || n > len(r.raw) {
962+ return ListExtensionsReply{}, false
963+ }
964+ it := NewStrIter(r.raw[off:], n)
965+ for it.Next() {
966+ off += it.Value().Size()
967+ }
968+ if it.Err() {
969+ return ListExtensionsReply{}, false
970+ }
971+ }
972+ if off > len(r.raw) {
973+ return ListExtensionsReply{}, false
974+ }
975+ return r, true
976+}
977+func (r ListExtensionsReply) Raw() []byte { return r.raw }
978+func (r ListExtensionsReply) NamesLen() uint8 { return uint8(r.raw[1:][0]) }
979+func (r ListExtensionsReply) Names() StrIter {
980+ off := 32
981+ return NewStrIter(r.raw[off:], int(r.NamesLen()))
982+}
983+
984+// GetKeyboardMappingReply is a zero-copy view over a GetKeyboardMapping reply; offsets count from reply byte 0.
985+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
986+type GetKeyboardMappingReply struct{ raw []byte }
987+
988+// ParseGetKeyboardMappingReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
989+func ParseGetKeyboardMappingReply(raw []byte) (GetKeyboardMappingReply, bool) {
990+ if len(raw) < 32 {
991+ return GetKeyboardMappingReply{}, false
992+ }
993+ r := GetKeyboardMappingReply{raw: raw}
994+ off := 32
995+ {
996+ n := int(binary.LittleEndian.Uint32(r.raw[4:]))
997+ if n < 0 || n > len(r.raw) {
998+ return GetKeyboardMappingReply{}, false
999+ }
1000+ off += n * 4
1001+ }
1002+ if off > len(r.raw) {
1003+ return GetKeyboardMappingReply{}, false
1004+ }
1005+ if off > len(r.raw) {
1006+ return GetKeyboardMappingReply{}, false
1007+ }
1008+ return r, true
1009+}
1010+func (r GetKeyboardMappingReply) Raw() []byte { return r.raw }
1011+func (r GetKeyboardMappingReply) KeysymsPerKeycode() byte { return byte(r.raw[1:][0]) }
1012+func (r GetKeyboardMappingReply) Keysyms() KeysymList {
1013+ off := 32
1014+ end := off + (int(binary.LittleEndian.Uint32(r.raw[4:])))*4
1015+ return KeysymList{b: r.raw[off:end:end]}
1016+}
1017+
1018+// GetKeyboardControlReply is a zero-copy view over a GetKeyboardControl reply; offsets count from reply byte 0.
1019+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
1020+type GetKeyboardControlReply struct{ raw []byte }
1021+
1022+// ParseGetKeyboardControlReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
1023+func ParseGetKeyboardControlReply(raw []byte) (GetKeyboardControlReply, bool) {
1024+ if len(raw) < 52 {
1025+ return GetKeyboardControlReply{}, false
1026+ }
1027+ r := GetKeyboardControlReply{raw: raw}
1028+ return r, true
1029+}
1030+func (r GetKeyboardControlReply) Raw() []byte { return r.raw }
1031+func (r GetKeyboardControlReply) GlobalAutoRepeat() AutoRepeatMode {
1032+ return AutoRepeatMode(r.raw[1:][0])
1033+}
1034+func (r GetKeyboardControlReply) LedMask() uint32 {
1035+ return uint32(binary.LittleEndian.Uint32(r.raw[8:]))
1036+}
1037+func (r GetKeyboardControlReply) KeyClickPercent() uint8 { return uint8(r.raw[12:][0]) }
1038+func (r GetKeyboardControlReply) BellPercent() uint8 { return uint8(r.raw[13:][0]) }
1039+func (r GetKeyboardControlReply) BellPitch() uint16 {
1040+ return uint16(binary.LittleEndian.Uint16(r.raw[14:]))
1041+}
1042+func (r GetKeyboardControlReply) BellDuration() uint16 {
1043+ return uint16(binary.LittleEndian.Uint16(r.raw[16:]))
1044+}
1045+func (r GetKeyboardControlReply) AutoRepeats() []byte {
1046+ off := 20
1047+ end := off + 32
1048+ return r.raw[off:end:end]
1049+}
1050+
1051+// GetPointerControlReply is a zero-copy view over a GetPointerControl reply; offsets count from reply byte 0.
1052+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
1053+type GetPointerControlReply struct{ raw []byte }
1054+
1055+// ParseGetPointerControlReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
1056+func ParseGetPointerControlReply(raw []byte) (GetPointerControlReply, bool) {
1057+ if len(raw) < 32 {
1058+ return GetPointerControlReply{}, false
1059+ }
1060+ r := GetPointerControlReply{raw: raw}
1061+ return r, true
1062+}
1063+func (r GetPointerControlReply) Raw() []byte { return r.raw }
1064+func (r GetPointerControlReply) AccelerationNumerator() uint16 {
1065+ return uint16(binary.LittleEndian.Uint16(r.raw[8:]))
1066+}
1067+func (r GetPointerControlReply) AccelerationDenominator() uint16 {
1068+ return uint16(binary.LittleEndian.Uint16(r.raw[10:]))
1069+}
1070+func (r GetPointerControlReply) Threshold() uint16 {
1071+ return uint16(binary.LittleEndian.Uint16(r.raw[12:]))
1072+}
1073+
1074+// GetScreenSaverReply is a zero-copy view over a GetScreenSaver reply; offsets count from reply byte 0.
1075+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
1076+type GetScreenSaverReply struct{ raw []byte }
1077+
1078+// ParseGetScreenSaverReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
1079+func ParseGetScreenSaverReply(raw []byte) (GetScreenSaverReply, bool) {
1080+ if len(raw) < 32 {
1081+ return GetScreenSaverReply{}, false
1082+ }
1083+ r := GetScreenSaverReply{raw: raw}
1084+ return r, true
1085+}
1086+func (r GetScreenSaverReply) Raw() []byte { return r.raw }
1087+func (r GetScreenSaverReply) Timeout() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[8:])) }
1088+func (r GetScreenSaverReply) Interval() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[10:])) }
1089+func (r GetScreenSaverReply) PreferBlanking() Blanking { return Blanking(r.raw[12:][0]) }
1090+func (r GetScreenSaverReply) AllowExposures() Exposures { return Exposures(r.raw[13:][0]) }
1091+
1092+// ListHostsReply is a zero-copy view over a ListHosts reply; offsets count from reply byte 0.
1093+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
1094+type ListHostsReply struct{ raw []byte }
1095+
1096+// ParseListHostsReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
1097+func ParseListHostsReply(raw []byte) (ListHostsReply, bool) {
1098+ if len(raw) < 32 {
1099+ return ListHostsReply{}, false
1100+ }
1101+ r := ListHostsReply{raw: raw}
1102+ off := 32
1103+ {
1104+ n := int(r.HostsLen())
1105+ if off > len(r.raw) || n < 0 || n > len(r.raw) {
1106+ return ListHostsReply{}, false
1107+ }
1108+ it := NewHostIter(r.raw[off:], n)
1109+ for it.Next() {
1110+ off += it.Value().Size()
1111+ }
1112+ if it.Err() {
1113+ return ListHostsReply{}, false
1114+ }
1115+ }
1116+ if off > len(r.raw) {
1117+ return ListHostsReply{}, false
1118+ }
1119+ return r, true
1120+}
1121+func (r ListHostsReply) Raw() []byte { return r.raw }
1122+func (r ListHostsReply) Mode() AccessControl { return AccessControl(r.raw[1:][0]) }
1123+func (r ListHostsReply) HostsLen() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[8:])) }
1124+func (r ListHostsReply) Hosts() HostIter {
1125+ off := 32
1126+ return NewHostIter(r.raw[off:], int(r.HostsLen()))
1127+}
1128+
1129+// SetPointerMappingReply is a zero-copy view over a SetPointerMapping reply; offsets count from reply byte 0.
1130+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
1131+type SetPointerMappingReply struct{ raw []byte }
1132+
1133+// ParseSetPointerMappingReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
1134+func ParseSetPointerMappingReply(raw []byte) (SetPointerMappingReply, bool) {
1135+ if len(raw) < 32 {
1136+ return SetPointerMappingReply{}, false
1137+ }
1138+ r := SetPointerMappingReply{raw: raw}
1139+ return r, true
1140+}
1141+func (r SetPointerMappingReply) Raw() []byte { return r.raw }
1142+func (r SetPointerMappingReply) Status() MappingStatus { return MappingStatus(r.raw[1:][0]) }
1143+
1144+// GetPointerMappingReply is a zero-copy view over a GetPointerMapping reply; offsets count from reply byte 0.
1145+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
1146+type GetPointerMappingReply struct{ raw []byte }
1147+
1148+// ParseGetPointerMappingReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
1149+func ParseGetPointerMappingReply(raw []byte) (GetPointerMappingReply, bool) {
1150+ if len(raw) < 32 {
1151+ return GetPointerMappingReply{}, false
1152+ }
1153+ r := GetPointerMappingReply{raw: raw}
1154+ off := 32
1155+ {
1156+ n := int(r.MapLen())
1157+ if n < 0 || n > len(r.raw) {
1158+ return GetPointerMappingReply{}, false
1159+ }
1160+ off += n * 1
1161+ }
1162+ if off > len(r.raw) {
1163+ return GetPointerMappingReply{}, false
1164+ }
1165+ if off > len(r.raw) {
1166+ return GetPointerMappingReply{}, false
1167+ }
1168+ return r, true
1169+}
1170+func (r GetPointerMappingReply) Raw() []byte { return r.raw }
1171+func (r GetPointerMappingReply) MapLen() uint8 { return uint8(r.raw[1:][0]) }
1172+func (r GetPointerMappingReply) Map() []byte {
1173+ off := 32
1174+ end := off + int(r.MapLen())
1175+ return r.raw[off:end:end]
1176+}
1177+
1178+// SetModifierMappingReply is a zero-copy view over a SetModifierMapping reply; offsets count from reply byte 0.
1179+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
1180+type SetModifierMappingReply struct{ raw []byte }
1181+
1182+// ParseSetModifierMappingReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
1183+func ParseSetModifierMappingReply(raw []byte) (SetModifierMappingReply, bool) {
1184+ if len(raw) < 32 {
1185+ return SetModifierMappingReply{}, false
1186+ }
1187+ r := SetModifierMappingReply{raw: raw}
1188+ return r, true
1189+}
1190+func (r SetModifierMappingReply) Raw() []byte { return r.raw }
1191+func (r SetModifierMappingReply) Status() MappingStatus { return MappingStatus(r.raw[1:][0]) }
1192+
1193+// GetModifierMappingReply is a zero-copy view over a GetModifierMapping reply; offsets count from reply byte 0.
1194+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
1195+type GetModifierMappingReply struct{ raw []byte }
1196+
1197+// ParseGetModifierMappingReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
1198+func ParseGetModifierMappingReply(raw []byte) (GetModifierMappingReply, bool) {
1199+ if len(raw) < 32 {
1200+ return GetModifierMappingReply{}, false
1201+ }
1202+ r := GetModifierMappingReply{raw: raw}
1203+ off := 32
1204+ {
1205+ n := (int(r.KeycodesPerModifier()) * 8)
1206+ if n < 0 || n > len(r.raw) {
1207+ return GetModifierMappingReply{}, false
1208+ }
1209+ off += n * 1
1210+ }
1211+ if off > len(r.raw) {
1212+ return GetModifierMappingReply{}, false
1213+ }
1214+ if off > len(r.raw) {
1215+ return GetModifierMappingReply{}, false
1216+ }
1217+ return r, true
1218+}
1219+func (r GetModifierMappingReply) Raw() []byte { return r.raw }
1220+func (r GetModifierMappingReply) KeycodesPerModifier() uint8 { return uint8(r.raw[1:][0]) }
1221+func (r GetModifierMappingReply) Keycodes() KeycodeList {
1222+ off := 32
1223+ end := off + (int(r.KeycodesPerModifier())*8)*1
1224+ return KeycodeList{b: r.raw[off:end:end]}
1225+}
1226+
1227+// DepthView is a zero-copy view over one wire-encoded Depth, yielded by DepthIter.
1228+// It shares the lifetime of the bytes it was taken from (for replies: until the Handler callback returns). Copy what you keep.
1229+type DepthView struct{ raw []byte }
1230+
1231+func (v DepthView) Raw() []byte { return v.raw }
1232+
1233+// Size is the element's wire size, including trailing alignment.
1234+func (v DepthView) Size() int { return len(v.raw) }
1235+func sizeDepth(p []byte) int {
1236+ if len(p) < 8 {
1237+ return -1
1238+ }
1239+ v := DepthView{raw: p}
1240+ _ = v
1241+ off := 8
1242+ {
1243+ n := int(v.VisualsLen())
1244+ if n < 0 || n > len(v.raw) {
1245+ return -1
1246+ }
1247+ off += n * 24
1248+ }
1249+ if off > len(v.raw) {
1250+ return -1
1251+ }
1252+ if off > len(v.raw) {
1253+ return -1
1254+ }
1255+ return off
1256+}
1257+func (v DepthView) Depth() uint8 { return uint8(v.raw[0:][0]) }
1258+func (v DepthView) VisualsLen() uint16 { return uint16(binary.LittleEndian.Uint16(v.raw[2:])) }
1259+func (v DepthView) Visuals() VisualtypeList {
1260+ off := 8
1261+ end := off + (int(v.VisualsLen()))*24
1262+ return VisualtypeList{b: v.raw[off:end:end]}
1263+}
1264+
1265+// DepthIter walks n consecutive Depth elements; Err reports a malformed length.
1266+// It shares the lifetime of the bytes it walks.
1267+type DepthIter struct {
1268+ b []byte
1269+ n int
1270+ v DepthView
1271+ err bool
1272+}
1273+
1274+// NewDepthIter iterates n elements encoded at the start of b.
1275+func NewDepthIter(b []byte, n int) DepthIter { return DepthIter{b: b, n: n} }
1276+func (it *DepthIter) Next() bool {
1277+ if it.n <= 0 || it.err {
1278+ return false
1279+ }
1280+ s := sizeDepth(it.b)
1281+ if s < 0 {
1282+ it.err = true
1283+ it.n = 0
1284+ return false
1285+ }
1286+ it.v = DepthView{raw: it.b[:s:s]}
1287+ it.b = it.b[s:]
1288+ it.n--
1289+ return true
1290+}
1291+func (it *DepthIter) Value() DepthView { return it.v }
1292+func (it *DepthIter) Err() bool { return it.err }
1293+
1294+// ScreenView is a zero-copy view over one wire-encoded Screen, yielded by ScreenIter.
1295+// It shares the lifetime of the bytes it was taken from (for replies: until the Handler callback returns). Copy what you keep.
1296+type ScreenView struct{ raw []byte }
1297+
1298+func (v ScreenView) Raw() []byte { return v.raw }
1299+
1300+// Size is the element's wire size, including trailing alignment.
1301+func (v ScreenView) Size() int { return len(v.raw) }
1302+func sizeScreen(p []byte) int {
1303+ if len(p) < 40 {
1304+ return -1
1305+ }
1306+ v := ScreenView{raw: p}
1307+ _ = v
1308+ off := 40
1309+ {
1310+ n := int(v.AllowedDepthsLen())
1311+ if off > len(v.raw) || n < 0 || n > len(v.raw) {
1312+ return -1
1313+ }
1314+ it := NewDepthIter(v.raw[off:], n)
1315+ for it.Next() {
1316+ off += it.Value().Size()
1317+ }
1318+ if it.Err() {
1319+ return -1
1320+ }
1321+ }
1322+ if off > len(v.raw) {
1323+ return -1
1324+ }
1325+ return off
1326+}
1327+func (v ScreenView) Root() Window { return Window(binary.LittleEndian.Uint32(v.raw[0:])) }
1328+func (v ScreenView) DefaultColormap() Colormap {
1329+ return Colormap(binary.LittleEndian.Uint32(v.raw[4:]))
1330+}
1331+func (v ScreenView) WhitePixel() uint32 { return uint32(binary.LittleEndian.Uint32(v.raw[8:])) }
1332+func (v ScreenView) BlackPixel() uint32 { return uint32(binary.LittleEndian.Uint32(v.raw[12:])) }
1333+func (v ScreenView) CurrentInputMasks() EventMask {
1334+ return EventMask(binary.LittleEndian.Uint32(v.raw[16:]))
1335+}
1336+func (v ScreenView) WidthInPixels() uint16 { return uint16(binary.LittleEndian.Uint16(v.raw[20:])) }
1337+func (v ScreenView) HeightInPixels() uint16 { return uint16(binary.LittleEndian.Uint16(v.raw[22:])) }
1338+func (v ScreenView) WidthInMillimeters() uint16 {
1339+ return uint16(binary.LittleEndian.Uint16(v.raw[24:]))
1340+}
1341+func (v ScreenView) HeightInMillimeters() uint16 {
1342+ return uint16(binary.LittleEndian.Uint16(v.raw[26:]))
1343+}
1344+func (v ScreenView) MinInstalledMaps() uint16 { return uint16(binary.LittleEndian.Uint16(v.raw[28:])) }
1345+func (v ScreenView) MaxInstalledMaps() uint16 { return uint16(binary.LittleEndian.Uint16(v.raw[30:])) }
1346+func (v ScreenView) RootVisual() Visualid { return Visualid(binary.LittleEndian.Uint32(v.raw[32:])) }
1347+func (v ScreenView) BackingStores() BackingStore { return BackingStore(v.raw[36:][0]) }
1348+func (v ScreenView) SaveUnders() bool { return (v.raw[37:][0] != 0) }
1349+func (v ScreenView) RootDepth() uint8 { return uint8(v.raw[38:][0]) }
1350+func (v ScreenView) AllowedDepthsLen() uint8 { return uint8(v.raw[39:][0]) }
1351+func (v ScreenView) AllowedDepths() DepthIter {
1352+ off := 40
1353+ return NewDepthIter(v.raw[off:], int(v.AllowedDepthsLen()))
1354+}
1355+
1356+// ScreenIter walks n consecutive Screen elements; Err reports a malformed length.
1357+// It shares the lifetime of the bytes it walks.
1358+type ScreenIter struct {
1359+ b []byte
1360+ n int
1361+ v ScreenView
1362+ err bool
1363+}
1364+
1365+// NewScreenIter iterates n elements encoded at the start of b.
1366+func NewScreenIter(b []byte, n int) ScreenIter { return ScreenIter{b: b, n: n} }
1367+func (it *ScreenIter) Next() bool {
1368+ if it.n <= 0 || it.err {
1369+ return false
1370+ }
1371+ s := sizeScreen(it.b)
1372+ if s < 0 {
1373+ it.err = true
1374+ it.n = 0
1375+ return false
1376+ }
1377+ it.v = ScreenView{raw: it.b[:s:s]}
1378+ it.b = it.b[s:]
1379+ it.n--
1380+ return true
1381+}
1382+func (it *ScreenIter) Value() ScreenView { return it.v }
1383+func (it *ScreenIter) Err() bool { return it.err }
1384+
1385+// SetupRequestView is a zero-copy view over one wire-encoded SetupRequest, yielded by SetupRequestIter.
1386+// It shares the lifetime of the bytes it was taken from (for replies: until the Handler callback returns). Copy what you keep.
1387+type SetupRequestView struct{ raw []byte }
1388+
1389+func (v SetupRequestView) Raw() []byte { return v.raw }
1390+
1391+// Size is the element's wire size, including trailing alignment.
1392+func (v SetupRequestView) Size() int { return len(v.raw) }
1393+func sizeSetupRequest(p []byte) int {
1394+ if len(p) < 12 {
1395+ return -1
1396+ }
1397+ v := SetupRequestView{raw: p}
1398+ _ = v
1399+ off := 12
1400+ {
1401+ n := int(v.AuthorizationProtocolNameLen())
1402+ if n < 0 || n > len(v.raw) {
1403+ return -1
1404+ }
1405+ off += n * 1
1406+ }
1407+ if off > len(v.raw) {
1408+ return -1
1409+ }
1410+ off = (off + 3) &^ 3
1411+ {
1412+ n := int(v.AuthorizationProtocolDataLen())
1413+ if n < 0 || n > len(v.raw) {
1414+ return -1
1415+ }
1416+ off += n * 1
1417+ }
1418+ if off > len(v.raw) {
1419+ return -1
1420+ }
1421+ off = (off + 3) &^ 3
1422+ if off > len(v.raw) {
1423+ return -1
1424+ }
1425+ return off
1426+}
1427+func (v SetupRequestView) ByteOrder() uint8 { return uint8(v.raw[0:][0]) }
1428+func (v SetupRequestView) ProtocolMajorVersion() uint16 {
1429+ return uint16(binary.LittleEndian.Uint16(v.raw[2:]))
1430+}
1431+func (v SetupRequestView) ProtocolMinorVersion() uint16 {
1432+ return uint16(binary.LittleEndian.Uint16(v.raw[4:]))
1433+}
1434+func (v SetupRequestView) AuthorizationProtocolNameLen() uint16 {
1435+ return uint16(binary.LittleEndian.Uint16(v.raw[6:]))
1436+}
1437+func (v SetupRequestView) AuthorizationProtocolDataLen() uint16 {
1438+ return uint16(binary.LittleEndian.Uint16(v.raw[8:]))
1439+}
1440+func (v SetupRequestView) AuthorizationProtocolName() []byte {
1441+ off := 12
1442+ end := off + int(v.AuthorizationProtocolNameLen())
1443+ return v.raw[off:end:end]
1444+}
1445+func (v SetupRequestView) AuthorizationProtocolData() []byte {
1446+ off := 12
1447+ {
1448+ n := int(v.AuthorizationProtocolNameLen())
1449+ off += n * 1
1450+ }
1451+ off = (off + 3) &^ 3
1452+ end := off + int(v.AuthorizationProtocolDataLen())
1453+ return v.raw[off:end:end]
1454+}
1455+
1456+// SetupRequestIter walks n consecutive SetupRequest elements; Err reports a malformed length.
1457+// It shares the lifetime of the bytes it walks.
1458+type SetupRequestIter struct {
1459+ b []byte
1460+ n int
1461+ v SetupRequestView
1462+ err bool
1463+}
1464+
1465+// NewSetupRequestIter iterates n elements encoded at the start of b.
1466+func NewSetupRequestIter(b []byte, n int) SetupRequestIter { return SetupRequestIter{b: b, n: n} }
1467+func (it *SetupRequestIter) Next() bool {
1468+ if it.n <= 0 || it.err {
1469+ return false
1470+ }
1471+ s := sizeSetupRequest(it.b)
1472+ if s < 0 {
1473+ it.err = true
1474+ it.n = 0
1475+ return false
1476+ }
1477+ it.v = SetupRequestView{raw: it.b[:s:s]}
1478+ it.b = it.b[s:]
1479+ it.n--
1480+ return true
1481+}
1482+func (it *SetupRequestIter) Value() SetupRequestView { return it.v }
1483+func (it *SetupRequestIter) Err() bool { return it.err }
1484+
1485+// SetupFailedView is a zero-copy view over one wire-encoded SetupFailed, yielded by SetupFailedIter.
1486+// It shares the lifetime of the bytes it was taken from (for replies: until the Handler callback returns). Copy what you keep.
1487+type SetupFailedView struct{ raw []byte }
1488+
1489+func (v SetupFailedView) Raw() []byte { return v.raw }
1490+
1491+// Size is the element's wire size, including trailing alignment.
1492+func (v SetupFailedView) Size() int { return len(v.raw) }
1493+func sizeSetupFailed(p []byte) int {
1494+ if len(p) < 8 {
1495+ return -1
1496+ }
1497+ v := SetupFailedView{raw: p}
1498+ _ = v
1499+ off := 8
1500+ {
1501+ n := int(v.ReasonLen())
1502+ if n < 0 || n > len(v.raw) {
1503+ return -1
1504+ }
1505+ off += n * 1
1506+ }
1507+ if off > len(v.raw) {
1508+ return -1
1509+ }
1510+ if off > len(v.raw) {
1511+ return -1
1512+ }
1513+ return off
1514+}
1515+func (v SetupFailedView) Status() uint8 { return uint8(v.raw[0:][0]) }
1516+func (v SetupFailedView) ReasonLen() uint8 { return uint8(v.raw[1:][0]) }
1517+func (v SetupFailedView) ProtocolMajorVersion() uint16 {
1518+ return uint16(binary.LittleEndian.Uint16(v.raw[2:]))
1519+}
1520+func (v SetupFailedView) ProtocolMinorVersion() uint16 {
1521+ return uint16(binary.LittleEndian.Uint16(v.raw[4:]))
1522+}
1523+func (v SetupFailedView) Length() uint16 { return uint16(binary.LittleEndian.Uint16(v.raw[6:])) }
1524+func (v SetupFailedView) Reason() []byte {
1525+ off := 8
1526+ end := off + int(v.ReasonLen())
1527+ return v.raw[off:end:end]
1528+}
1529+
1530+// SetupFailedIter walks n consecutive SetupFailed elements; Err reports a malformed length.
1531+// It shares the lifetime of the bytes it walks.
1532+type SetupFailedIter struct {
1533+ b []byte
1534+ n int
1535+ v SetupFailedView
1536+ err bool
1537+}
1538+
1539+// NewSetupFailedIter iterates n elements encoded at the start of b.
1540+func NewSetupFailedIter(b []byte, n int) SetupFailedIter { return SetupFailedIter{b: b, n: n} }
1541+func (it *SetupFailedIter) Next() bool {
1542+ if it.n <= 0 || it.err {
1543+ return false
1544+ }
1545+ s := sizeSetupFailed(it.b)
1546+ if s < 0 {
1547+ it.err = true
1548+ it.n = 0
1549+ return false
1550+ }
1551+ it.v = SetupFailedView{raw: it.b[:s:s]}
1552+ it.b = it.b[s:]
1553+ it.n--
1554+ return true
1555+}
1556+func (it *SetupFailedIter) Value() SetupFailedView { return it.v }
1557+func (it *SetupFailedIter) Err() bool { return it.err }
1558+
1559+// SetupAuthenticateView is a zero-copy view over one wire-encoded SetupAuthenticate, yielded by SetupAuthenticateIter.
1560+// It shares the lifetime of the bytes it was taken from (for replies: until the Handler callback returns). Copy what you keep.
1561+type SetupAuthenticateView struct{ raw []byte }
1562+
1563+func (v SetupAuthenticateView) Raw() []byte { return v.raw }
1564+
1565+// Size is the element's wire size, including trailing alignment.
1566+func (v SetupAuthenticateView) Size() int { return len(v.raw) }
1567+func sizeSetupAuthenticate(p []byte) int {
1568+ if len(p) < 8 {
1569+ return -1
1570+ }
1571+ v := SetupAuthenticateView{raw: p}
1572+ _ = v
1573+ off := 8
1574+ {
1575+ n := (int(v.Length()) * 4)
1576+ if n < 0 || n > len(v.raw) {
1577+ return -1
1578+ }
1579+ off += n * 1
1580+ }
1581+ if off > len(v.raw) {
1582+ return -1
1583+ }
1584+ if off > len(v.raw) {
1585+ return -1
1586+ }
1587+ return off
1588+}
1589+func (v SetupAuthenticateView) Status() uint8 { return uint8(v.raw[0:][0]) }
1590+func (v SetupAuthenticateView) Length() uint16 { return uint16(binary.LittleEndian.Uint16(v.raw[6:])) }
1591+func (v SetupAuthenticateView) Reason() []byte {
1592+ off := 8
1593+ end := off + (int(v.Length()) * 4)
1594+ return v.raw[off:end:end]
1595+}
1596+
1597+// SetupAuthenticateIter walks n consecutive SetupAuthenticate elements; Err reports a malformed length.
1598+// It shares the lifetime of the bytes it walks.
1599+type SetupAuthenticateIter struct {
1600+ b []byte
1601+ n int
1602+ v SetupAuthenticateView
1603+ err bool
1604+}
1605+
1606+// NewSetupAuthenticateIter iterates n elements encoded at the start of b.
1607+func NewSetupAuthenticateIter(b []byte, n int) SetupAuthenticateIter {
1608+ return SetupAuthenticateIter{b: b, n: n}
1609+}
1610+func (it *SetupAuthenticateIter) Next() bool {
1611+ if it.n <= 0 || it.err {
1612+ return false
1613+ }
1614+ s := sizeSetupAuthenticate(it.b)
1615+ if s < 0 {
1616+ it.err = true
1617+ it.n = 0
1618+ return false
1619+ }
1620+ it.v = SetupAuthenticateView{raw: it.b[:s:s]}
1621+ it.b = it.b[s:]
1622+ it.n--
1623+ return true
1624+}
1625+func (it *SetupAuthenticateIter) Value() SetupAuthenticateView { return it.v }
1626+func (it *SetupAuthenticateIter) Err() bool { return it.err }
1627+
1628+// SetupView is a zero-copy view over one wire-encoded Setup, yielded by SetupIter.
1629+// It shares the lifetime of the bytes it was taken from (for replies: until the Handler callback returns). Copy what you keep.
1630+type SetupView struct{ raw []byte }
1631+
1632+func (v SetupView) Raw() []byte { return v.raw }
1633+
1634+// Size is the element's wire size, including trailing alignment.
1635+func (v SetupView) Size() int { return len(v.raw) }
1636+func sizeSetup(p []byte) int {
1637+ if len(p) < 40 {
1638+ return -1
1639+ }
1640+ v := SetupView{raw: p}
1641+ _ = v
1642+ off := 40
1643+ {
1644+ n := int(v.VendorLen())
1645+ if n < 0 || n > len(v.raw) {
1646+ return -1
1647+ }
1648+ off += n * 1
1649+ }
1650+ if off > len(v.raw) {
1651+ return -1
1652+ }
1653+ off = (off + 3) &^ 3
1654+ {
1655+ n := int(v.PixmapFormatsLen())
1656+ if n < 0 || n > len(v.raw) {
1657+ return -1
1658+ }
1659+ off += n * 8
1660+ }
1661+ if off > len(v.raw) {
1662+ return -1
1663+ }
1664+ {
1665+ n := int(v.RootsLen())
1666+ if off > len(v.raw) || n < 0 || n > len(v.raw) {
1667+ return -1
1668+ }
1669+ it := NewScreenIter(v.raw[off:], n)
1670+ for it.Next() {
1671+ off += it.Value().Size()
1672+ }
1673+ if it.Err() {
1674+ return -1
1675+ }
1676+ }
1677+ if off > len(v.raw) {
1678+ return -1
1679+ }
1680+ return off
1681+}
1682+func (v SetupView) Status() uint8 { return uint8(v.raw[0:][0]) }
1683+func (v SetupView) ProtocolMajorVersion() uint16 {
1684+ return uint16(binary.LittleEndian.Uint16(v.raw[2:]))
1685+}
1686+func (v SetupView) ProtocolMinorVersion() uint16 {
1687+ return uint16(binary.LittleEndian.Uint16(v.raw[4:]))
1688+}
1689+func (v SetupView) Length() uint16 { return uint16(binary.LittleEndian.Uint16(v.raw[6:])) }
1690+func (v SetupView) ReleaseNumber() uint32 { return uint32(binary.LittleEndian.Uint32(v.raw[8:])) }
1691+func (v SetupView) ResourceIdBase() uint32 { return uint32(binary.LittleEndian.Uint32(v.raw[12:])) }
1692+func (v SetupView) ResourceIdMask() uint32 { return uint32(binary.LittleEndian.Uint32(v.raw[16:])) }
1693+func (v SetupView) MotionBufferSize() uint32 { return uint32(binary.LittleEndian.Uint32(v.raw[20:])) }
1694+func (v SetupView) VendorLen() uint16 { return uint16(binary.LittleEndian.Uint16(v.raw[24:])) }
1695+func (v SetupView) MaximumRequestLength() uint16 {
1696+ return uint16(binary.LittleEndian.Uint16(v.raw[26:]))
1697+}
1698+func (v SetupView) RootsLen() uint8 { return uint8(v.raw[28:][0]) }
1699+func (v SetupView) PixmapFormatsLen() uint8 { return uint8(v.raw[29:][0]) }
1700+func (v SetupView) ImageByteOrder() ImageOrder { return ImageOrder(v.raw[30:][0]) }
1701+func (v SetupView) BitmapFormatBitOrder() ImageOrder { return ImageOrder(v.raw[31:][0]) }
1702+func (v SetupView) BitmapFormatScanlineUnit() uint8 { return uint8(v.raw[32:][0]) }
1703+func (v SetupView) BitmapFormatScanlinePad() uint8 { return uint8(v.raw[33:][0]) }
1704+func (v SetupView) MinKeycode() Keycode { return Keycode(v.raw[34:][0]) }
1705+func (v SetupView) MaxKeycode() Keycode { return Keycode(v.raw[35:][0]) }
1706+func (v SetupView) Vendor() []byte {
1707+ off := 40
1708+ end := off + int(v.VendorLen())
1709+ return v.raw[off:end:end]
1710+}
1711+func (v SetupView) PixmapFormats() FormatList {
1712+ off := 40
1713+ {
1714+ n := int(v.VendorLen())
1715+ off += n * 1
1716+ }
1717+ off = (off + 3) &^ 3
1718+ end := off + (int(v.PixmapFormatsLen()))*8
1719+ return FormatList{b: v.raw[off:end:end]}
1720+}
1721+func (v SetupView) Roots() ScreenIter {
1722+ off := 40
1723+ {
1724+ n := int(v.VendorLen())
1725+ off += n * 1
1726+ }
1727+ off = (off + 3) &^ 3
1728+ {
1729+ n := int(v.PixmapFormatsLen())
1730+ off += n * 8
1731+ }
1732+ return NewScreenIter(v.raw[off:], int(v.RootsLen()))
1733+}
1734+
1735+// SetupIter walks n consecutive Setup elements; Err reports a malformed length.
1736+// It shares the lifetime of the bytes it walks.
1737+type SetupIter struct {
1738+ b []byte
1739+ n int
1740+ v SetupView
1741+ err bool
1742+}
1743+
1744+// NewSetupIter iterates n elements encoded at the start of b.
1745+func NewSetupIter(b []byte, n int) SetupIter { return SetupIter{b: b, n: n} }
1746+func (it *SetupIter) Next() bool {
1747+ if it.n <= 0 || it.err {
1748+ return false
1749+ }
1750+ s := sizeSetup(it.b)
1751+ if s < 0 {
1752+ it.err = true
1753+ it.n = 0
1754+ return false
1755+ }
1756+ it.v = SetupView{raw: it.b[:s:s]}
1757+ it.b = it.b[s:]
1758+ it.n--
1759+ return true
1760+}
1761+func (it *SetupIter) Value() SetupView { return it.v }
1762+func (it *SetupIter) Err() bool { return it.err }
1763+
1764+// StrView is a zero-copy view over one wire-encoded Str, yielded by StrIter.
1765+// It shares the lifetime of the bytes it was taken from (for replies: until the Handler callback returns). Copy what you keep.
1766+type StrView struct{ raw []byte }
1767+
1768+func (v StrView) Raw() []byte { return v.raw }
1769+
1770+// Size is the element's wire size, including trailing alignment.
1771+func (v StrView) Size() int { return len(v.raw) }
1772+func sizeStr(p []byte) int {
1773+ if len(p) < 1 {
1774+ return -1
1775+ }
1776+ v := StrView{raw: p}
1777+ _ = v
1778+ off := 1
1779+ {
1780+ n := int(v.NameLen())
1781+ if n < 0 || n > len(v.raw) {
1782+ return -1
1783+ }
1784+ off += n * 1
1785+ }
1786+ if off > len(v.raw) {
1787+ return -1
1788+ }
1789+ if off > len(v.raw) {
1790+ return -1
1791+ }
1792+ return off
1793+}
1794+func (v StrView) NameLen() uint8 { return uint8(v.raw[0:][0]) }
1795+func (v StrView) Name() []byte { off := 1; end := off + int(v.NameLen()); return v.raw[off:end:end] }
1796+
1797+// StrIter walks n consecutive Str elements; Err reports a malformed length.
1798+// It shares the lifetime of the bytes it walks.
1799+type StrIter struct {
1800+ b []byte
1801+ n int
1802+ v StrView
1803+ err bool
1804+}
1805+
1806+// NewStrIter iterates n elements encoded at the start of b.
1807+func NewStrIter(b []byte, n int) StrIter { return StrIter{b: b, n: n} }
1808+func (it *StrIter) Next() bool {
1809+ if it.n <= 0 || it.err {
1810+ return false
1811+ }
1812+ s := sizeStr(it.b)
1813+ if s < 0 {
1814+ it.err = true
1815+ it.n = 0
1816+ return false
1817+ }
1818+ it.v = StrView{raw: it.b[:s:s]}
1819+ it.b = it.b[s:]
1820+ it.n--
1821+ return true
1822+}
1823+func (it *StrIter) Value() StrView { return it.v }
1824+func (it *StrIter) Err() bool { return it.err }
1825+
1826+// HostView is a zero-copy view over one wire-encoded Host, yielded by HostIter.
1827+// It shares the lifetime of the bytes it was taken from (for replies: until the Handler callback returns). Copy what you keep.
1828+type HostView struct{ raw []byte }
1829+
1830+func (v HostView) Raw() []byte { return v.raw }
1831+
1832+// Size is the element's wire size, including trailing alignment.
1833+func (v HostView) Size() int { return len(v.raw) }
1834+func sizeHost(p []byte) int {
1835+ if len(p) < 4 {
1836+ return -1
1837+ }
1838+ v := HostView{raw: p}
1839+ _ = v
1840+ off := 4
1841+ {
1842+ n := int(v.AddressLen())
1843+ if n < 0 || n > len(v.raw) {
1844+ return -1
1845+ }
1846+ off += n * 1
1847+ }
1848+ if off > len(v.raw) {
1849+ return -1
1850+ }
1851+ off = (off + 3) &^ 3
1852+ if off > len(v.raw) {
1853+ return -1
1854+ }
1855+ return off
1856+}
1857+func (v HostView) Family() Family { return Family(v.raw[0:][0]) }
1858+func (v HostView) AddressLen() uint16 { return uint16(binary.LittleEndian.Uint16(v.raw[2:])) }
1859+func (v HostView) Address() []byte {
1860+ off := 4
1861+ end := off + int(v.AddressLen())
1862+ return v.raw[off:end:end]
1863+}
1864+
1865+// HostIter walks n consecutive Host elements; Err reports a malformed length.
1866+// It shares the lifetime of the bytes it walks.
1867+type HostIter struct {
1868+ b []byte
1869+ n int
1870+ v HostView
1871+ err bool
1872+}
1873+
1874+// NewHostIter iterates n elements encoded at the start of b.
1875+func NewHostIter(b []byte, n int) HostIter { return HostIter{b: b, n: n} }
1876+func (it *HostIter) Next() bool {
1877+ if it.n <= 0 || it.err {
1878+ return false
1879+ }
1880+ s := sizeHost(it.b)
1881+ if s < 0 {
1882+ it.err = true
1883+ it.n = 0
1884+ return false
1885+ }
1886+ it.v = HostView{raw: it.b[:s:s]}
1887+ it.b = it.b[s:]
1888+ it.n--
1889+ return true
1890+}
1891+func (it *HostIter) Value() HostView { return it.v }
1892+func (it *HostIter) Err() bool { return it.err }
1893+
1894+// AtomList is a borrowed view over a wire list of Atom. It shares the lifetime of the bytes it was taken from; copy what you keep.
1895+type AtomList struct{ b []byte }
1896+
1897+func (l AtomList) Len() int { return len(l.b) / 4 }
1898+func (l AtomList) At(i int) Atom { return Atom(binary.LittleEndian.Uint32(l.b[i*4:])) }
1899+
1900+// CharinfoList is a borrowed view over a wire list of Charinfo. It shares the lifetime of the bytes it was taken from; copy what you keep.
1901+type CharinfoList struct{ b []byte }
1902+
1903+func (l CharinfoList) Len() int { return len(l.b) / 12 }
1904+func (l CharinfoList) At(i int) Charinfo { return GetCharinfo(l.b[i*12:]) }
1905+
1906+// ColormapList is a borrowed view over a wire list of Colormap. It shares the lifetime of the bytes it was taken from; copy what you keep.
1907+type ColormapList struct{ b []byte }
1908+
1909+func (l ColormapList) Len() int { return len(l.b) / 4 }
1910+func (l ColormapList) At(i int) Colormap { return Colormap(binary.LittleEndian.Uint32(l.b[i*4:])) }
1911+
1912+// FontpropList is a borrowed view over a wire list of Fontprop. It shares the lifetime of the bytes it was taken from; copy what you keep.
1913+type FontpropList struct{ b []byte }
1914+
1915+func (l FontpropList) Len() int { return len(l.b) / 8 }
1916+func (l FontpropList) At(i int) Fontprop { return GetFontprop(l.b[i*8:]) }
1917+
1918+// FormatList is a borrowed view over a wire list of Format. It shares the lifetime of the bytes it was taken from; copy what you keep.
1919+type FormatList struct{ b []byte }
1920+
1921+func (l FormatList) Len() int { return len(l.b) / 8 }
1922+func (l FormatList) At(i int) Format { return GetFormat(l.b[i*8:]) }
1923+
1924+// KeycodeList is a borrowed view over a wire list of Keycode. It shares the lifetime of the bytes it was taken from; copy what you keep.
1925+type KeycodeList struct{ b []byte }
1926+
1927+func (l KeycodeList) Len() int { return len(l.b) / 1 }
1928+func (l KeycodeList) At(i int) Keycode { return Keycode(l.b[i*1:][0]) }
1929+
1930+// KeysymList is a borrowed view over a wire list of Keysym. It shares the lifetime of the bytes it was taken from; copy what you keep.
1931+type KeysymList struct{ b []byte }
1932+
1933+func (l KeysymList) Len() int { return len(l.b) / 4 }
1934+func (l KeysymList) At(i int) Keysym { return Keysym(binary.LittleEndian.Uint32(l.b[i*4:])) }
1935+
1936+// RgbList is a borrowed view over a wire list of Rgb. It shares the lifetime of the bytes it was taken from; copy what you keep.
1937+type RgbList struct{ b []byte }
1938+
1939+func (l RgbList) Len() int { return len(l.b) / 8 }
1940+func (l RgbList) At(i int) Rgb { return GetRgb(l.b[i*8:]) }
1941+
1942+// TimecoordList is a borrowed view over a wire list of Timecoord. It shares the lifetime of the bytes it was taken from; copy what you keep.
1943+type TimecoordList struct{ b []byte }
1944+
1945+func (l TimecoordList) Len() int { return len(l.b) / 8 }
1946+func (l TimecoordList) At(i int) Timecoord { return GetTimecoord(l.b[i*8:]) }
1947+
1948+// Uint32List is a borrowed view over a wire list of uint32. It shares the lifetime of the bytes it was taken from; copy what you keep.
1949+type Uint32List struct{ b []byte }
1950+
1951+func (l Uint32List) Len() int { return len(l.b) / 4 }
1952+func (l Uint32List) At(i int) uint32 { return uint32(binary.LittleEndian.Uint32(l.b[i*4:])) }
1953+
1954+// VisualtypeList is a borrowed view over a wire list of Visualtype. It shares the lifetime of the bytes it was taken from; copy what you keep.
1955+type VisualtypeList struct{ b []byte }
1956+
1957+func (l VisualtypeList) Len() int { return len(l.b) / 24 }
1958+func (l VisualtypeList) At(i int) Visualtype { return GetVisualtype(l.b[i*24:]) }
1959+
1960+// WindowList is a borrowed view over a wire list of Window. It shares the lifetime of the bytes it was taken from; copy what you keep.
1961+type WindowList struct{ b []byte }
1962+
1963+func (l WindowList) Len() int { return len(l.b) / 4 }
1964+func (l WindowList) At(i int) Window { return Window(binary.LittleEndian.Uint32(l.b[i*4:])) }

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 1

↑↓ moveenter openesc close