master
go 80 lines 2.12 KB
Raw
1 // STRING_REVERSE codec (method 3) -- variable-length payload:
2 //
3 // [0:4] u32 str_offset (from payload start, always 8)
4 // [4:8] u32 str_length (excluding NUL)
5 // [8:N+1] string data + NUL
6
7 package protocol
8
9 const StringReverseHdrSize = 8
10
11 // StringReverseView is the decoded result of a STRING_REVERSE payload.
12 type StringReverseView struct {
13 Str string
14 StrLen uint32
15 }
16
17 // StringReverseEncode writes a STRING_REVERSE payload into buf.
18 // Returns total bytes written, or 0 if buf is too small.
19 func StringReverseEncode(s string, buf []byte) int {
20 total := StringReverseHdrSize + len(s) + 1
21 if len(buf) < total {
22 return 0
23 }
24 strLen, ok := checkedU32Int(len(s))
25 if !ok {
26 return 0
27 }
28 ne.PutUint32(buf[0:4], uint32(StringReverseHdrSize)) // str_offset
29 ne.PutUint32(buf[4:8], strLen) // str_length
30 if len(s) > 0 {
31 copy(buf[8:8+len(s)], s)
32 }
33 buf[8+len(s)] = 0 // NUL terminator
34 return total
35 }
36
37 // StringReverseDecode decodes a STRING_REVERSE payload from buf.
38 func StringReverseDecode(buf []byte) (StringReverseView, error) {
39 if len(buf) < StringReverseHdrSize {
40 return StringReverseView{}, ErrTruncated
41 }
42 strOffset, err := checkedWireU32Int(buf, 0)
43 if err != nil {
44 return StringReverseView{}, err
45 }
46 strLength, err := checkedWireU32Int(buf, 4)
47 if err != nil {
48 return StringReverseView{}, err
49 }
50 strLength32 := ne.Uint32(buf[4:8])
51 strEnd, ok := checkedAddInt(strOffset, strLength)
52 if !ok {
53 return StringReverseView{}, ErrOutOfBounds
54 }
55 strNulEnd, ok := checkedAddInt(strEnd, 1)
56 if !ok || strNulEnd > len(buf) {
57 return StringReverseView{}, ErrOutOfBounds
58 }
59 if buf[strEnd] != 0 {
60 return StringReverseView{}, ErrMissingNul
61 }
62 return StringReverseView{
63 Str: string(buf[strOffset:strEnd]),
64 StrLen: strLength32,
65 }, nil
66 }
67
68 // DispatchStringReverse decodes request, calls handler, encodes response.
69 func DispatchStringReverse(req []byte, resp []byte, handler func(string) (string, bool)) (int, bool) {
70 view, err := StringReverseDecode(req)
71 if err != nil {
72 return 0, false
73 }
74 result, ok := handler(view.Str)
75 if !ok {
76 return 0, false
77 }
78 n := StringReverseEncode(result, resp)
79 return n, n > 0
80 }