forked from elastic/beats
-
Notifications
You must be signed in to change notification settings - Fork 0
/
prog.go
133 lines (123 loc) · 2.72 KB
/
prog.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package dtfmt
import (
"errors"
"time"
)
type prog struct {
p []byte
}
const (
opNone byte = iota
opCopy1 // copy next byte
opCopy2 // copy next 2 bytes
opCopy3 // copy next 3 bytes
opCopy4 // copy next 4 bytes
opCopyShort // [op, len, content[len]]
opCopyLong // [op, len1, len, content[len1<<8 + len]]
opNum // [op, ft]
opNumPadded // [op, ft, digits]
opTwoDigit // [op, ft]
opTextShort // [op, ft]
opTextLong // [op, ft]
)
func (p prog) eval(bytes []byte, ctx *ctx, t time.Time) ([]byte, error) {
for i := 0; i < len(p.p); {
op := p.p[i]
i++
switch op {
case opNone:
case opCopy1:
bytes = append(bytes, p.p[i])
i++
case opCopy2:
bytes = append(bytes, p.p[i], p.p[i+1])
i += 2
case opCopy3:
bytes = append(bytes, p.p[i], p.p[i+1], p.p[i+2])
i += 3
case opCopy4:
bytes = append(bytes, p.p[i], p.p[i+1], p.p[i+2], p.p[i+3])
i += 4
case opCopyShort:
l := int(p.p[i])
i++
bytes = append(bytes, p.p[i:i+l]...)
i += l
case opCopyLong:
l := int(p.p[i])<<8 | int(p.p[i+1])
i += 2
bytes = append(bytes, p.p[i:i+l]...)
i += l
case opNum:
ft := fieldType(p.p[i])
i++
v, err := getIntField(ft, ctx, t)
if err != nil {
return bytes, err
}
bytes = appendUnpadded(bytes, v)
case opNumPadded:
ft, digits := fieldType(p.p[i]), int(p.p[i+1])
i += 2
v, err := getIntField(ft, ctx, t)
if err != nil {
return bytes, err
}
bytes = appendPadded(bytes, v, digits)
case opTwoDigit:
ft := fieldType(p.p[i])
i++
v, err := getIntField(ft, ctx, t)
if err != nil {
return bytes, err
}
bytes = appendPadded(bytes, v%100, 2)
case opTextShort:
ft := fieldType(p.p[i])
i++
s, err := getTextFieldShort(ft, ctx, t)
if err != nil {
return bytes, err
}
bytes = append(bytes, s...)
case opTextLong:
ft := fieldType(p.p[i])
i++
s, err := getTextField(ft, ctx, t)
if err != nil {
return bytes, err
}
bytes = append(bytes, s...)
default:
return bytes, errors.New("unknown opcode")
}
}
return bytes, nil
}
func makeProg(b ...byte) (prog, error) {
return prog{b}, nil
}
func makeCopy(b []byte) (prog, error) {
l := len(b)
switch l {
case 0:
return prog{}, nil
case 1:
return makeProg(opCopy1, b[0])
case 2:
return makeProg(opCopy2, b[0], b[1])
case 3:
return makeProg(opCopy2, b[0], b[1], b[2])
case 4:
return makeProg(opCopy2, b[0], b[1], b[2], b[3])
}
if l < 256 {
return prog{append([]byte{opCopyShort, byte(l)}, b...)}, nil
}
if l < (1 << 16) {
l1 := byte(l >> 8)
l2 := byte(l)
return prog{append([]byte{opCopyLong, l1, l2}, b...)}, nil
}
return prog{}, errors.New("literal too long")
}